gpt4 book ai didi

java - 为可信空间定制 Spring Security

转载 作者:行者123 更新时间:2023-11-30 06:04:54 25 4
gpt4 key购买 nike

服务在受信任空间中的网关之后工作(gateWay 验证 OAuth token 并仅向服务提供唯一的用户 ID,否则它会重定向以验证服务)。

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

所以我添加了CustomUserDetailsS​​ervice

@Service("userDetailsService")public class CustomUserDetailsService implements UserDetailsService {    @Autowired(required = false)    private ContextSsoActiveProfileIdProvider contextSsoActiveProfileIdProvider;    @Autowired    private GrantedAuthorityService grantedAuthorityService;    @Override    public User loadUserByUsername(final String username) throws UsernameNotFoundException {        // verify it with authentication service, but there is not token, userId only, so trust to gateway service.        return new User(                String.valueOf(contextSsoActiveProfileIdProvider.getSsoActiveProfileId()),                "authenticatedWithGateWay",                grantedAuthorityService.getGrantedAuthoritiesForCurrentUser()        );    }}

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

该服务在受信任的区域中启动,因此我以下一种方式配置了安全性:

@EnableWebSecurity@Configurationpublic class SecurityConfiguration extends WebSecurityConfigurerAdapter {    @Autowired    private UserDetailsService userDetailsService;    @Override    protected void configure(HttpSecurity http) throws Exception {        http                .authorizeRequests()                .antMatchers("/**").permitAll();    }    @Override    protected UserDetailsService userDetailsService() {        return userDetailsService;    }}

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

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

更多问题症状:

  • CustomUserDetailsS​​ervice.loadUserByUsername(..) 从未被调用;
  • 在 REST API 部分 @AuthenticationPrincipal User activeUser 为 null
  • 在 REST API 部分 Principal principal 也为 null

最佳答案

可信空间问题与匿名用户身份识别有类似的解决方案(我在做这件事的时候就得出了这个结论。)

简答

可信空间不需要授权,但不会调用 UserDetailsS​​ervice,因为默认只使用 AnonymousAuthenticationProviderAnonymousAuthenticationFilter。实现基于 AnonymousAuthenticationFilter 覆盖 createAuthentication 并将默认值 (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:

@Componentpublic 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
}
}

现在看起来好多了,因为 identifiableAnonymousAuthenticationFilter 被注入(inject)到 AnonymousConfigurer 中。请注意基于 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 时,由于条件 if(SecurityContextHolder.getContext ().getAuthentication() == null)(见之前的方法)

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

警告

或者有人会想 - 在 IdentifiableAnonymousAuthenticationFilter 中无条件地添加 doFilter 覆盖(这是 hack):

    @Override    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)            throws IOException, ServletException {        SecurityContextHolder.getContext().setAuthentication(createAuthentication((HttpServletRequest) req));        if (logger.isDebugEnabled()) {            logger.debug("Populated SecurityContextHolder with anonymous token: '"                    + SecurityContextHolder.getContext().getAuthentication() + "'");        }        chain.doFilter(req, res);    }

如果您需要 spring security 处理授权/认证用户,这是 Not Acceptable ,但在某些情况下就足够了。

附言

解决方案的某些部分可以改进,但我希望总体上思路清晰。

关于java - 为可信空间定制 Spring Security,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48173057/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com