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

Spring Security自定义身份验证过滤器和授权

刘承悦
2023-03-14

我实现了一个自定义的身份验证过滤器,效果很好。在设置会话并将身份验证对象添加到安全上下文后,我使用外部身份提供程序并重定向到最初请求的URL。

安全配置

@EnableWebSecurity(debug = true)
@Configuration
class SecurityConfig extends WebSecurityConfigurerAdapter {

    // this is needed to pass the authentication manager into our custom security filter
    @Bean
    @Override
    AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean()
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
                //.antMatchers("/admin/test").hasRole("METADATA_CURATORZ")
                .antMatchers("/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(new CustomSecurityFilter(authenticationManagerBean()), UsernamePasswordAuthenticationFilter.class)
    }
}

过滤逻辑

目前,我的自定义过滤器(身份确认后)只需硬编码一个角色:

SimpleGrantedAuthority myrole = new SimpleGrantedAuthority("METADATA_CURATORZ")
                return new PreAuthenticatedAuthenticationToken(securityUser, null, [myrole])

然后将该身份验证对象(上面返回)添加到我的SecurityContext,然后再重定向到所需的endpoint:

SecurityContextHolder.getContext(). setAuthentiation(身份验证)

控制器终结点

  @RequestMapping(path = '/admin/test', method = GET, produces = 'text/plain')
  String test(HttpServletRequest request) {
    Authentication auth = SecurityContextHolder.getContext().getAuthentication()

    String roles = auth.getAuthorities()
    return "roles: ${roles}"
  }

然后,该endpoint在浏览器中生成响应:

“角色:[METADATA\u CURATORZ]”

太好了。所以我的身份验证和将角色应用于我的用户效果很好。

现在,如果我从安全配置中取消注释这一行:

/。antMatchers(“/admin/test”)。hasRole(“METADATA\u CURATORZ”)

我再也无法访问该资源并获得403——尽管我们已经证明角色已经设置好了。

这对我来说似乎完全是荒谬的,但我不是Spring Security专家。

我可能错过了一些非常简单的事情。有什么想法吗?

我有一些问题:

  • 我的自定义过滤器是否需要放在特定内置过滤器之前,以确保在执行该过滤器后执行授权步骤
  • 在请求周期中何时进行antMatcher/hasRole检查
  • 我是否需要更改我在安全配置链中调用的顺序,以及我应该如何理解当前编写的配置?很明显,它没有做我认为应该做的事情

共有1个答案

吴才俊
2023-03-14

我的自定义过滤器是否需要放在特定内置过滤器之前,以确保在执行该过滤器后执行授权步骤?

您的过滤器必须位于FilterSecurityInterceptor之前,因为这是进行授权和身份验证的地方。此过滤器是最后调用的过滤器之一。

现在关于过滤器的最佳位置可能在哪里,这真的取决于情况。例如,您真的希望您的过滤器位于匿名认证过滤器之前,因为如果没有,未经身份验证的用户将始终使用匿名认证令牌进行“身份验证”到您的过滤器被调用时。

您可以在FilterComparator中查看过滤器的默认顺序。AbstractPreAuthenticatedProcessingFilter几乎与您正在做的事情相对应,它按过滤器的顺序排列,让您知道可以将自己的过滤器放在哪里。无论如何,过滤器的顺序应该没有问题。

在请求周期中何时进行antMatcher/hasRole检查?

所有这些都发生在FilterSecurityInterceptor中,更准确地说,发生在其父级AbstractSecurityInterceptor中:

protected InterceptorStatusToken beforeInvocation(Object object) {

    Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
            .getAttributes(object);

    if (attributes == null || attributes.isEmpty()) {
        ...
    }

    ...

    Authentication authenticated = authenticateIfRequired();

    // Attempt authorization
    try {
        this.accessDecisionManager.decide(authenticated, object, attributes);
    }
    catch (AccessDeniedException accessDeniedException) {

        ...

        throw accessDeniedException;
    }

额外信息:本质上,FilterSecurityInterceptor有一个包含Map的ExpressionBasedFilterInvocationSecurityMetadataSource

我是否需要更改我在安全配置链中调用的顺序,以及我应该如何理解当前编写的配置?很明显,它没有做我认为应该做的事情。

不,你的过滤器应该没有任何问题。作为补充说明,除了您的配置(HttpSecurity http)方法之外,您扩展的websecurityconfig适配器还有一些默认值:

http
    .csrf().and()
    .addFilter(new WebAsyncManagerIntegrationFilter())
    .exceptionHandling().and()
    .headers().and()
    .sessionManagement().and()
    .securityContext().and()
    .requestCache().and()
    .anonymous().and()
    .servletApi().and()
    .apply(new DefaultLoginPageConfigurer<>()).and()
    .logout();

如果您想确切了解它们的作用以及它们添加了什么过滤器,可以查看HttpSecurity。

当您执行以下操作时:

.authorizeRequests()
    .antMatchers("/admin/test").hasRole("METADATA_CURATORZ")

...搜索的角色是"ROLE_METADATA_CURATORZ"。为什么?ExpressionUrlAuthorizationConfigrer的静态hasRole(String角色)方法最终处理"METADATA_CURATORZ"

if (role.startsWith("ROLE_")) {
    throw new IllegalArgumentException(
                "role should not start with 'ROLE_' since it is automatically inserted. Got '"
                        + role + "'");
    }
    return "hasRole('ROLE_" + role + "')";
}

因此,您的授权表达式变为“hasRole('ROLE\u METADATA\u CURATORZ')”,这最终调用了SecurityExpressionRoot上的方法hasRole('ROLE\u METADATA\u CURATORZ'),该方法反过来在Authentication的权限中搜索角色。

改变

SimpleGrantedAuthority myrole = new SimpleGrantedAuthority("METADATA_CURATORZ");

到:

SimpleGrantedAuthority myrole = new SimpleGrantedAuthority("ROLE_METADATA_CURATORZ");

 类似资料:
  • 问题内容: 这是我的情况: 一个Web应用程序对许多应用程序执行某种SSO 登录的用户,而不是单击链接,该应用就会向正确的应用发布包含用户信息(名称,pwd [无用],角色)的帖子 我正在其中一个应用程序上实现SpringSecurity以从其功能中受益(会话中的权限,其类提供的方法等) 因此,我需要开发一个 自定义过滤器 -我猜想-能够从请求中检索用户信息,通过自定义 DetailsUserSe

  • 现在我的是的一部分,位于正确的位置。平滑。 但是,由于是,它会被引导拾取并作为筛选器包含。所以我的过滤链看起来真的像: SSOAuthenticationFilter(由于是,因此包含) FilterChainProxy(spring自动配置) ... SecurityContextPersistenceFilter SSOAuthenticationFilter(包含在) ... 显然,我希望在

  • 嗨,我正在学习Spring安全,我被困在自定义认证过滤器中。我有以下文件:主应用程序文件: : 我的安全配置文件安全: 最后我的CustomAuthentication filter文件:< code > customauthenticationfilter . Java : 因此,我已经将<code>attemptAuthentication</code>方法放在日志中,但似乎请求没有到达那里。

  • 我的问题是我的SpringConfig类中筛选器的配置。我希望筛选器仅在请求是/authenticate URL时生效,我已将.antmatcher(“/authenticate/**”)添加到筛选器配置中。 当所有其他URL中的该行不再安全时,我可以手动导航到/home,而不进行身份验证,删除该行并对/home进行身份验证。 我应该声明一个只适用于特定URL的筛选器吗? 我如何在维护其他URL的

  • 我正在尝试实现一个自定义密钥克拉克身份验证器SPI,用于针对外部数据源/REST服务进行身份验证。计划是将它们迁移到Keycloak。 成功后,在keycloak数据源上创建用户。 创建自定义映射器以在令牌上添加额外的用户属性。 我正在遵循官方指南https://www.keycloak.org/docs/latest/server_development/index.html#_auth_spi

  • 我试图使用keycloak只用于身份验证,并有自己的自定义过滤器用于授权。因此理想的流程是:首先,Keycloak filter对请求进行身份验证,并在上下文中设置身份验证对象。然后,我的自定义过滤器应该运行,它应该获得现有的身份验证对象,在该身份验证对象中添加权限,并将其设置回上下文中。 因此,首先,在speing引导应用程序中使用keycloak是正确的方法吗?如果是,那么如何使我的过滤器在过