Spring Security oauth2Login OAuth2UserService 认证后未执行

Posted

技术标签:

【中文标题】Spring Security oauth2Login OAuth2UserService 认证后未执行【英文标题】:Spring Security oauth2Login OAuth2UserService not executed after authentication 【发布时间】:2020-12-29 05:16:06 【问题描述】:

我有一个由 Keycloak 保护的 Spring Boot Admin 应用程序,我定义了一个具有领域角色 ACTUATOR 的用户。 问题是认证后 Spring Security 无法访问领域角色。我可以看到授予的权限:Granted Authorities: ROLE_USER, SCOPE_actuator_access, SCOPE_profile'

查看文档,我找到了这个部分:Delegation-based strategy with OAuth2UserService,这是我的配置:

这是我的配置:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure( HttpSecurity http ) throws Exception 
        http.csrf().disable().cors().disable();
        http.authorizeRequests()
                .antMatchers( "/error","/instances", "/**/*.css", "/**/img/**", "/**/third-party/**", "/*.js" )
                .permitAll()
                .anyRequest().hasRole( "ACTUATOR" )
                .and()
                .oauth2Login( oauth2 -> oauth2.userInfoEndpoint(
                        userInfo -> userInfo.oidcUserService( this.oidcUserService() ) ) );
    

    // I just copy-paste the doc's code to play with it...
    private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() 

        final OidcUserService delegate = new OidcUserService();

        return ( userRequest ) -> 
            OidcUser oidcUser = delegate.loadUser( userRequest );

            //TODO find a way to extract realm roles 
            OAuth2AccessToken accessToken = userRequest.getAccessToken();

            Set<GrantedAuthority> mappedAuthorities = new HashSet<>();

            oidcUser = new DefaultOidcUser( mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo() );

            return oidcUser;
        ;
    

我希望使用 oidcUserService() 方法从令牌中提取 Keycloak 领域角色,但该方法根本没有执行。我的意思是从 Keycloak 成功验证并重定向到应用程序后,oidcUserService() 方法不会执行。好像只在应用启动时执行,很奇怪。

问题是如何在这种情况下检索领域角色?

编辑

我在这里添加了一个示例项目:https://github.com/akuma8/sba-keycloak-spring-security

安全配置在application.ymlSecurityConfig 类中

【问题讨论】:

【参考方案1】:

我找到了为什么验证后没有调用oidcUserService() 方法。原因是令牌的类型,我从 Spring Security 文档中愚蠢地复制了代码,而没有注意该信息。

在文档中它是关于 OidcUserRequest 而在我的例子中是 OAuth2UserRequest,所以这是 OAUTH2OIDC 之间的冲突。将方法更改为:

private OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService() 
   // code extracting authorities from JWT here


解决了我的问题。我现在可以从访问令牌中获取 Keycloak 领域角色。

【讨论】:

【参考方案2】:

我不知道为什么没有调用这个 oidcUserService。您可以改用 JwtAuthenticationConverter 并将您的 JWT 映射到您需要的任何角色。

这有点棘手,所以这里有两个例子:

https://dev.to/toojannarong/spring-security-with-jwt-the-easiest-way-2i43(最新但有点过于宽泛,请查看“自定义声明”部分) https://***.com/a/58234971/1722236(已过时)

注意我不知道你是否应该在解析之前自己检查 JWT 签名,或者 Spring OAuth 是否会这样做。这值得检查。

【讨论】:

感谢您的建议,但我想避免使用 Keycloak 适配器。我使用提供完全 Oauth2 支持的 Spring security 5。唯一的问题是我们必须自定义很多东西。 @akuma8 你能在 Github 上放一个示例项目吗?如果不了解您所谈论的所有自定义,很难弄清楚为什么它不起作用...... 解析JWT适用于资源服务器的情况,在我的情况下并非如此。我有一些项目使用这种方法,因为Authorization 标头中存在不记名令牌。此外,如您所见,jwt() 方法遵循oauth2ResourceServer() 元素,在我的情况下,我使用oauth2Login() 对不起,我还是没明白。您的授权服务器是 Keycloak。我了解 Spring Boot 管理应用程序包含您要保护的资源。如果您的应用程序只是一个 Oauth2 提供程序,那么它提供什么访问权限?此外,如果不解析 JWT 声明并(除其他外)将它们映射到角色,您使用的 DefaultOidcUser 构造函数是什么?您打算如何在不解析 JWT(或让 spring oauth lib 为您完成)的情况下获得正确的角色? SBA 不提供任何资源,它是一个受 Keycloak 保护的 ui 应用程序,但它可以受到任何 IAM 提供商的保护。我知道我必须解析 JWT,但使用 Spring Security 5,使用 oauth2ResourceServer() 并不是最好的方法。使用oauth2ResourceServer() 不会将用户重定向到授权服务器进行身份验证。 oauth2ResourceServer() 是一种被动方式,资源服务器仅验证提供的令牌是否正确,但不会重定向以进行授权,而 oauthLogin() 则可以。我想我找到了解决方案,我会告诉你的。谢谢

以上是关于Spring Security oauth2Login OAuth2UserService 认证后未执行的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security:2.4 Getting Spring Security

没有 JSP 的 Spring Security /j_spring_security_check

Spring-Security

Spring Security 登录错误:HTTP 状态 404 - /j_spring_security_check

未调用 Spring Security j_spring_security_check

Spring Security入门(3-7)Spring Security处理页面的ajax请求