当前位置: 首页 > 知识库问答 >
问题:

自定义受信任空间的spring安全性

韩禄
2023-03-14

服务工作在可信空间中的网关之后(网关验证OAuth令牌,并只给服务唯一的用户ID,在其他情况下,它重定向认证服务)。

我想在服务中使用spring安全,以能够验证用户ID的权限。

因此,我添加了CustomUserDetailsService

@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,GetGrantedAuthorityService.GetGrantedAuthoritiesForCurrentUser()返回权限。

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

@EnableWebSecurity
@Configuration
public 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();或其他配置部分。

更多问题症状:

  • CustomUserDetailsService.LoadUserByUserName(..)从不调用
  • REST API部分@AuthenticationPrincipal User ActiveUser为空
  • 在REST API部分principal上也为null

共有1个答案

陈琪
2023-03-14

可信空间问题有类似于匿名用户标识的解决方案(我在研究这个问题时已经得出了这个结论)

受信任的空间不需要授权,但不会调用UserDetailsService,因为默认情况下只使用AnonymousAuthenticationProviderAnonymousAuthenticationFilter。基于AnonymousAuthenticationFilter实现自定义筛选器已经足够好了,它覆盖CreateAuthentication并用自定义筛选器(CustomAnonymousAuthenticationFilter)替换默认值(AnonymousAuthenticationFilter):

    @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();
        }
    }

我发现如果user没有得到授权,就永远不会调用CustomUserDetailsService。继续研究的重点是AnonymousAuthenticationFilter,它负责创建匿名用户信息。因此,其根本目的是用my IdentifiableAnonymousAuthenticationFilter替换AnonymousAuthenticationFilter,其中一些方法应该被覆盖:

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

将其注入配置

@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被注入到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()
      // ...

如果应用程序被修复,我不会关心它,但是AnonymousAuthenticationFilter调用的时间早于IdentifiableAnonymousAuthenticationFilter。和doFilter将不正确身份验证放入SecurityContextHolder。

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

因此,使用magic annotation@Order来管理配置加载顺序,为WebSecurityConfigurerAdapter配置提供修复配置将是非常好的。

或者有人会想--在IdentifiableAnonymousAuthenticationFilter中无条件添加doFilter重写(这是黑客):

    @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安全,这是不可接受的,但在某些情况下,这就足够了。

解决办法的某些部分可以改进,但我希望这个想法总体上是清楚的。

 类似资料:
  • 我正在使用这个环境: Spring 4.0.5 Spring security 3.2.4 在我的环境中,我有一个SSO系统,我需要在这个系统中集成我的web应用程序。这个系统是私人产品。SSO机制的最终结果是在请求头中放置一个参数。所以我在申请中应该做的是: null 此场景类似于CAS集成场景;所以我从CAS集成着手;我写了我的自定义过滤器,我写了我的自定义入口点和处理请求所需的所有其他类,但

  • 我们正在构建一个通过RabbitMQ接收消息的Spring Boot应用程序(2.0.4版本)。因此,包含与rabbit相关的配置: 配置: 原因:java.lang.IllegalArgumentException:类“My.Fancy.Package.Clazz”不在受信任的包[java.util,java.lang]中。如果您认为反序列化该类是安全的,请提供它的名称。如果序列化仅由受信任的源

  • 我有一个带有OAuth2授权和资源服务器的Spring引导设置。用户可以通过向发出POST请求来获取令牌。到目前为止,一切都很好。 但是,我不想通过基本auth保护,而是通过自定义安全过滤器。 一些简单的例子如何实现这一点将是非常有帮助的。谢谢!

  • 如何在链顶部的Spring Security链中插入多个自定义过滤器? 我可以通过在="FIRST"之后使用和之后尝试多个

  • 我有一个Keycloak连接器,它允许我通过SSO检索用户的用户名。我想使用这个用户名来认证用户,并在数据库中查找他的权限,并将这个用户权限注入到spring security中,以便能够使用它的功能。 我用自定义的UserDetailsService创建了一个自定义的authenticationProvider,但我一直面临的问题是,我每次都被重定向到spring security登录页面。我认

  • 问题内容: 如果我正在使用eval()评估Python字符串,并且具有类似这样的类: 如果我不信任该字符串,会有哪些安全风险?尤其是: 是eval(string, {“f”: Foo()}, {})不安全的?也就是说,你可以从Foo实例访问os或sys还是不安全的东西? 是eval(string, {}, {})不安全的?也就是说,我可以完全通过len和list之类的内置工具访问os或sys吗?