Spring OAuth2 - 客户端凭据授予类型中的用户信息

Posted

技术标签:

【中文标题】Spring OAuth2 - 客户端凭据授予类型中的用户信息【英文标题】:Spring OAuth2 - User info in Client Credentials grant type 【发布时间】:2019-05-11 03:36:21 【问题描述】:

我一直在开发 Spring Cloud(带有 Netflix OSS 堆栈)微服务架构有一段时间了。如您所料,我已将授权服务器分离为独立的微服务。我的前端应用程序使用“密码”授权类型进行用户登录。但是,对于从前端服务到其他后端服务的其余调用,我使用“客户端凭据”授权类型。客户端凭据授予类型也用于其他后端服务。通过这样做,我无法知道谁是请求的实际调用者(当前登录用户)。有没有办法将主体的身份验证和授权信息注入到客户端凭据授予中颁发的令牌中?

我的授权服务器配置类

@Configuration
@EnableAuthorizationServer
@Order(Ordered.HIGHEST_PRECEDENCE)
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter 

@Autowired
private AuthenticationManager authenticationManager;

@Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception 
    oauthServer.tokenKeyAccess("permitAll()")
        .checkTokenAccess("isAuthenticated()");


@Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception 
    clients.inMemory()
        .withClient("testclient")
        .secret("nooptestsecret")
        .authorizedGrantTypes("authorization_code","password","client_credentials")
        .scopes("ui")
        .autoApprove(true)
    // .accessTokenValiditySeconds(3600)
    .and()
        .withClient("backend-service")
        .secret("noopbackendsecret")
        .authorizedGrantTypes("client_credentials","refresh_token")
        .scopes("server")
         .autoApprove(true)

@Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
    endpoints.authenticationManager(authenticationManager);
    endpoints.tokenEnhancer(tokenEnhancer());
    endpoints.tokenStore(tokenStore());


@Bean
public TokenStore tokenStore() 
    //return new JdbcTokenStore(dataSource);
    return new InMemoryTokenStore();

@Bean
@Primary
public AuthorizationServerTokenServices tokenServices() 
    DefaultTokenServices tokenServices = new DefaultTokenServices();
    tokenServices.setTokenEnhancer(tokenEnhancer());
    tokenServices.setTokenStore(tokenStore());
    return tokenServices;


@Bean
public TokenEnhancer tokenEnhancer() 
    return new CustomTokenEnhancer();

安全配置类

@Configuration
@Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter 

@Override
protected void configure(HttpSecurity http) throws Exception 

    http.csrf().disable()
            .requestMatchers()
                .antMatchers("/login", "/oauth/authorize")
                .and()
                .authorizeRequests()
                .antMatchers("/resources/**", "/src/main/webapp/**","/css/**","/images/**").permitAll()
            .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
            .and()
            .logout()
            .permitAll().and().httpBasic().disable();



@Override
public void configure(WebSecurity web) throws Exception 
    web.ignoring().antMatchers("/static/**","/resources/**", "/src/main/webapp/**","/css/**","/images/**");


@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception 
    return super.authenticationManagerBean();


@Override
protected void configure(final AuthenticationManagerBuilder auth) throws Exception 
    auth.inMemoryAuthentication().withUser("admin").password("noopa1b2c3#").roles("User");



我尝试实现一个 Token Enhancer 类来传播令牌中的其他数据。但是,我认为这不是我想要实现的正确且安全的方法。

public class CustomTokenEnhancer implements TokenEnhancer 
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) 
    final Map<String, Object> additionalInfo = new HashMap<>();

    additionalInfo.put("customInfo", "testdata");

    ((DefaultOAuth2AccessToken) oAuth2AccessToken).setAdditionalInformation(additionalInfo);

    return oAuth2AccessToken;
    

我们将不胜感激。

【问题讨论】:

【参考方案1】:

如果您使用的是使用客户端凭据生成的 oauth 令牌,那么您将无法获取用户信息。您只能获取请求的来源(客户端)。

如果想要跨微服务的用户信息,那么您必须使用密码授予类型来生成 oauth 令牌。

【讨论】:

在这种情况下,使用 JWT 代替 oauth 令牌是我最好的选择吗? 另外,如果你不想使用 JWT,你可以制作一个特殊的 API 来检索当前用户信息。在此 API 中,您需要从 SecurityContextHolder 获取用户信息(如果您传递有效令牌,则它返回授权用户信息)。您无需在此 API 中传递任何请求参数,您所需要的只是在安全上下文中。 好主意。 @AnatoliyKorovin 你认为使用 Map 在 CustomTokenEnhancer 类中保存 oAuth2AccessToken.toString(), oAuth2Authentication.getUserAuthentication().getPrincipal() 键值对是否明智,并使用 setAdditionalInformation() 方法从客户端应用程序中获取它getAdditionalInformation() 方法?这样,我们会将当前用户的令牌和他/她的身份验证对象存储在地图中,并将其传递给客户端应用程序。

以上是关于Spring OAuth2 - 客户端凭据授予类型中的用户信息的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2 和 OAuth2 客户端凭据不受支持的授权类型

如何在使用 OAuth2 的资源所有者密码凭据授予类型时对客户端凭据保密

OAuth2:JWT授权授予和客户端凭据授权与JWT客户端身份验证之间的区别是什么?

Spring Security 5 客户端凭据授予与 azure 广告

如何获取 Spring Boot 和 OAuth2 示例以使用默认密码授予凭据以外的其他凭据

Spring 网站的 Spring Security Oauth2