为可信空间定制Spring Security

服务在可信空间中的网关之后工作(gateWayvalidationOAuth令牌并仅向服务提供唯一的用户ID,其他情况下它重定向以validation服务)。

我想在服务中使用spring security来validationuserId的权限。

所以我添加了CustomUserDetailsService

 @Service( “的UserDetailsS​​ervice”)
公共类CustomUserDetailsS​​ervice实现UserDetailsS​​ervice {
     @Autowired(required = false)
     private ContextSsoActiveProfileIdProvider contextSsoActiveProfileIdProvider;
     @Autowired
     private GrantedAuthorityService grantAuthorityService;

     @覆盖
     public User loadUserByUsername(final String username)throws UsernameNotFoundException {
         //使用身份validation服务validation它,但没有令牌,仅限userId,因此信任网关服务。
        返回新用户(
                将String.valueOf(contextSsoActiveProfileIdProvider.getSsoActiveProfileId()),
                 “authenticatedWithGateWay”
                 grantedAuthorityService.getGrantedAuthoritiesForCurrentUser()
         );
     }
 }

其中contextSsoActiveProfileIdProvider.getSsoActiveProfileId()返回uniqueUserId和grantedAuthorityService.getGrantedAuthoritiesForCurrentUser()返回权限。

该服务在受信任区域中启动,因此我已通过下一步方式配置安全性:

 @EnableWebSecurity
 @组态
公共类SecurityConfiguration扩展了WebSecurityConfigurerAdapter {
     @Autowired
     private UserDetailsS​​ervice userDetailsS​​ervice;

     @覆盖
     protected void configure(HttpSecurity http)抛出Exception {
         HTTP
                 .authorizeRequests()
                 .antMatchers( “/ **”)permitAll();
     }

     @覆盖
     protected UserDetailsS​​ervice userDetailsS​​ervice(){
         return userDetailsS​​ervice;
     }
 }

我需要为所有URI( http.authorizeRequests().antMatchers("/**").permitAll(); )提供所有用户的免费访问权限(不触发登录提供),但似乎禁止触发下一个注释@PreAuthorize处理程序, @PreFilter@PostAuthorize@PostFilter

我想我在这里误解了http.authorizeRequests().antMatchers("/**").permitAll(); 或与其他配置部分。

更多问题症状:

  • 从不调用CustomUserDetailsService.loadUserByUsername(..) ;
  • 在REST API部分@AuthenticationPrincipal User activeUser为null
  • 在REST API部分, Principal principal也为null

可信空间问题与匿名用户识别有类似的解决方案(我在处理它时已经做了这个结论。)

简短的回答

可信空间不需要授权,但不会调用UserDetailsS​​ervice ,因为默认情况下仅使用AnonymousAuthenticationProviderAnonymousAuthenticationFilter 。 基于AnonymousAuthenticationFilter覆盖createAuthentication并使用自定义( CustomAnonymousAuthenticationFilter )替换默认( AnonymousAuthenticationFilter )是很好的实现自定义filter:

     @组态
     public static class NoAuthConfigurationAdapter扩展WebSecurityConfigurerAdapter {
         @Autowired
         private UserDetailsS​​ervice userDetailsS​​ervice;
         @Autowired
         private IdentifiableAnonymousAuthenticationFilter identifiableAnonymousAuthenticationFilter;

         @覆盖
         protected void configure(HttpSecurity http)抛出Exception {
             http.anonymous()authenticationFilter(identifiableAnonymousAuthenticationFilter)。
             http.antMatcher( “/ **”)。authorizeRequests()
                     .anyRequest()permitAll();
         }
     }

完整答案

我发现如果用户未经授权,将永远不会调用CustomUserDetailsS​​ervice 。 持续研究注意AnonymousAuthenticationFilter ,它负责创建匿名用户信息。 因此,目的是用我的IdentifiableAnonymousAuthenticationFilter替换AnonymousAuthenticationFilter ,其中应该覆盖一些方法:

 @零件
 public class IdentifiableAnonymousAuthenticationFilter extends AnonymousAuthenticationFilter {
     public static final String KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER
             =“Key.IdentifiableAnonymousAuthenticationFilter”;
     @Autowired
     private CustomUserDetailsS​​ervice userDetailsS​​ervice;
     @Autowired
     private GrantedAuthorityService grantAuthorityService;
     private AuthenticationDetailsS​​ource authenticationDetailsS​​ource
             = new WebAuthenticationDetailsS​​ource();

     public IdentifiableAnonymousAuthenticationFilter(){
        此(KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER);
     }

     public IdentifiableAnonymousAuthenticationFilter(String key){
        超级(键);
     }

     @覆盖
     protected Authentication createAuthentication(HttpServletRequest request){
         AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(
                 KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER,
                 userDetailsS​​ervice.loadCurrentUser(请求),
                 grantedAuthorityService.getGrantedAuthoritiesForCurrentUser());
         auth.setDetails(authenticationDetailsS​​ource.buildDetails(请求));
        返回认证;
     }
 }

将其注入配置中

 @Configuration public class IdentifyAnonymousConfigurationAdapter extends WebSecurityConfigurerAdapter { @Autowired private IdentifiableAnonymousAuthenticationFilter identifiableAnonymousAuthenticationFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.anonymous().authenticationFilter(identifiableAnonymousAuthenticationFilter); // ... some other configurations } } 

现在看起来好多了,因为在AnonymousConfigurer中注入了identifiableAnonymousAuthenticationFilter 。 请注意基于WebSecurityConfigurerAdapter的配置。 如果你有几个,其中一个不会设置customAnonymousAuthenticationFilter但配置早于自定义..你将获得AnonymousAuthenticationFilter的默认实例(默认情况下在WebSecurityConfigurerAdapter配置):

   protected final HttpSecurity getHttp()抛出Exception {
       // ...
       HTTP
         .csrf()和()
         .addFilter(new WebAsyncManagerIntegrationFilter())
         .exceptionHandling()和()
         .headers()和()
         .sessionManagement()和()
         .securityContext()和()
         .requestCache()和()
         .anonymous()和()
       // ...

如果应用程序已修复,我会关心它,但AnonymousAuthenticationFilter早于IdentifiableAnonymousAuthenticationFilter调用。 并且doFilterSecurityContextHolder放入incorrect身份validation中。

 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { if(SecurityContextHolder.getContext().getAuthentication() == null) { SecurityContextHolder.getContext().setAuthentication(this.createAuthentication((HttpServletRequest)req)); if(this.logger.isDebugEnabled()) { this.logger.debug("Populated SecurityContextHolder with anonymous token: '" + SecurityContextHolder.getContext().getAuthentication() + "'"); } } else if(this.logger.isDebugEnabled()) { this.logger.debug("SecurityContextHolder not populated with anonymous token, as it already contained: '" + SecurityContextHolder.getContext().getAuthentication() + "'"); } chain.doFilter(req, res); } 

因此,当下次为IdentifiableAnonymousAuthenticationFilter调用doFilter时,由于条件if(SecurityContextHolder.getContext().getAuthentication() == null)它不会替换Authentication if(SecurityContextHolder.getContext().getAuthentication() == null) (请参阅之前的方法)。

因此,使用魔术注释@Order管理配置加载顺序来修复WebSecurityConfigurerAdapter配置的配置非常好。

警告

或者有人会想 – 在没有条件的情况下添加doFilter覆盖IdentifiableAnonymousAuthenticationFilter (它是黑客 ):

     @覆盖
     public void doFilter(ServletRequest req,ServletResponse res,FilterChain chain)
            抛出IOException,ServletException {
         SecurityContextHolder.getContext()。setAuthentication(createAuthentication((HttpServletRequest)req));
         if(logger.isDebugEnabled()){
             logger.debug(“带有匿名标记的填充SecurityContextHolder:'”
                     + SecurityContextHolder.getContext()。getAuthentication()+“'”);
         }
         chain.doFilter(req,res);
     }

如果你需要处理授权/认证用户的弹簧安全性是不可接受的,但在某些情况下它就足够了。

PS

解决方案的某些部分可以改进,但我希望这个想法一般都很明确。