服务在网关在受信任空间中运行之后(gateWay验证OAuth令牌,并仅向服务提供唯一的用户ID,否则它将重定向到身份验证服务)。

我想在服务中使用Spring Security来验证userId的权限。

所以我加了CustomUserDetailsService

@Service(“ userDetailsS​​ervice”)
公共类CustomUserDetailsS​​ervice实现UserDetailsS​​ervice {
    @Autowired(必填=假)
    私有ContextSsoActiveProfileIdProvider contextSsoActiveProfileIdProvider;
    @Autowired
    私有GrantedAuthorityService grantAuthorityService;

    @Override
    公共用户loadUserByUsername(最终字符串用户名)抛出UsernameNotFoundException {
        //使用身份验证服务验证它,但没有令牌,仅用户ID,因此信任网关服务。
        返回新用户(
                String.valueOf(contextSsoActiveProfileIdProvider.getSsoActiveProfileId()),
                “ authenticatedWithGateWay”,
                allowedAuthorityService.getGrantedAuthoritiesForCurrentUser()
        );
    }
}


其中contextSsoActiveProfileIdProvider.getSsoActiveProfileId()返回uniqueUserId,grantAuthorityService.getGrantedAuthoritiesForCurrentUser()返回权限。

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

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

    @Override
    受保护的void configure(HttpSecurity http)抛出异常{
        http
                .authorizeRequests()
                .antMatchers(“ / **”)。permitAll();
    }

    @Override
    受保护的UserDetailsS​​ervice userDetailsS​​ervice(){
        返回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的自定义过滤器,并用自定义1(AnonymousAuthenticationFilter)替换默认值(CustomAnonymousAuthenticationFilter):

    @Configuration
    public static class NoAuthConfigurationAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private UserDetailsService userDetailsService;
        @Autowired
        private IdentifiableAnonymousAuthenticationFilter identifiableAnonymousAuthenticationFilter;

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.anonymous().authenticationFilter(identifiableAnonymousAuthenticationFilter);
            http.antMatcher("/**").authorizeRequests()
                    .anyRequest().permitAll();
        }
    }

Full answer

I found out that CustomUserDetailsService will never be called if user is not authorized. Continuing research pay attention on the AnonymousAuthenticationFilter which is responsible for creating anonymous user info. So in the very and purpose is to replace the AnonymousAuthenticationFilter with my IdentifiableAnonymousAuthenticationFilter where some methods should be overridden:

@Component
public class IdentifiableAnonymousAuthenticationFilter extends AnonymousAuthenticationFilter {
    public static final String KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER
            = "Key.IdentifiableAnonymousAuthenticationFilter";
    @Autowired
    private CustomUserDetailsService userDetailsService;
    @Autowired
    private GrantedAuthorityService grantedAuthorityService;
    private AuthenticationDetailsSource authenticationDetailsSource
            = new WebAuthenticationDetailsSource();

    public IdentifiableAnonymousAuthenticationFilter() {
        this(KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER);
    }

    public IdentifiableAnonymousAuthenticationFilter(String key) {
        super(key);
    }

    @Override
    protected Authentication createAuthentication(HttpServletRequest request) {
        AnonymousAuthenticationToken auth = new AnonymousAuthenticationToken(
                KEY_IDENTIFIABLE_ANONYMOUS_AUTHENTICATION_FILTER,
                userDetailsService.loadCurrentUser(request),
                grantedAuthorityService.getGrantedAuthoritiesForCurrentUser());
        auth.setDetails(authenticationDetailsSource.buildDetails(request));
        return auth;
    }
}

to inject it into configuration

@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,而是配置为早于custom ..,您将获得AnonymousAuthenticationFilter的默认实例(默认情况下在WebSecurityConfigurerAdapter中配置):

  protected final HttpSecurity getHttp() throws Exception {
      //...
      http
        .csrf().and()
        .addFilter(new WebAsyncManagerIntegrationFilter())
        .exceptionHandling().and()
        .headers().and()
        .sessionManagement().and()
        .securityContext().and()
        .requestCache().and()
        .anonymous().and()
      // ...

I would not care about it if application fixed, but AnonymousAuthenticationFilter called earlier than IdentifiableAnonymousAuthenticationFilter. And doFilter puts into SecurityContextHolder incorrect Authentication.

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时,由于条件Authentication,它不会替换if(SecurityContextHolder.getContext().getAuthentication() == null)(请参见前面的方法)。

因此,提供一种配置非常好,其中使用魔术批注@Order修复WebSecurityConfigurerAdapter配置以管理配置加载顺序。

警告

或者有人会想-在没有条件的情况下在IdentifiableAnonymousAuthenticationFilter中添加doFilter覆盖(这是hack):

    @Override
    公共无效doFilter(ServletRequest req,ServletResponse res,FilterChain链)
            引发IOException,ServletException {
        SecurityContextHolder.getContext()。setAuthentication(createAuthentication((HttpServletRequest)req));
        如果(logger.isDebugEnabled()){
            logger.debug(“带有匿名令牌的已填充SecurityContextHolder:'”
                    + SecurityContextHolder.getContext()。getAuthentication()+“'”);
        }
        chain.doFilter(req,res);
    }


如果您需要通过处理授权的/已认证的用户来确保弹簧安全性,那么这是不可接受的,但是在某些情况下,这就足够了。

附言

解决方案的某些部分可以改进,但我希望这个想法总体上是明确的。

09-11 18:08