Spring Boot 2.0.0 + OAuth2

Posted

技术标签:

【中文标题】Spring Boot 2.0.0 + OAuth2【英文标题】: 【发布时间】:2018-08-13 20:10:30 【问题描述】:

Spring Boot 2 + Sping Security OAuth2 是否仍然支持@AuthorizationServer 注解?通过阅读发行说明,有些东西还没有被移植:

Oauth2 Support

这里是我build.grade的相关部分:

身份验证服务器

// security
compile "org.springframework.boot:spring-boot-starter-security:$springBootVersion"
// oauth
// https://mvnrepository.com/artifact/org.springframework.security.oauth/spring-security-oauth2
compile "org.springframework.security.oauth:spring-security-oauth2:2.2.1.RELEASE"

客户端服务器

// support for Oauth2 user token services not yet migrated into Spring Boot 2.0
compile "org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.1.BUILD-SNAPSHOT"

现在,当我尝试将客户端 ID 和客户端密码以 Basic Authentication 传递给 /oauth/token 时,我的授权服务器 Oauth2 端点只返回 401。传入用户名和密码会给出不同的代码路径。所以看起来 OAuth 过滤器没有完全排列好。

我也发现了这个:Spring Boot 2 OAuth2 starter changes。

是否有配置更新或者我需要一组不同的 gradle 依赖项来将授权服务器恢复到之前的状态?

谢谢!


更新

我想结束这个问题的循环。除了加密客户端机密。自 Spring OAuth 2.3.2 起,RedisTokenStore 问题也已得到解决:Spring OAuth 2.3.2

【问题讨论】:

所以 oauth2 支持尚不支持 Spring Security?我对 Spring Security 5 + Spring Boot 2 感到困惑。我将更多地研究 org.springframework.security.oauth.boot:spring-security-oauth2-autoconfigure:2.0.1.BUILD-SNAPSHOT 【参考方案1】:

Spring Security 5 使用了现代化的密码存储,见OAuth2 Autoconfig:

如果您使用自己的授权服务器配置通过ClientDetailsServiceConfigurer的实例配置有效客户端列表如下所示,请注意您在此处配置的密码受Spring Security 5附带的现代化密码存储的约束.

要解决您的问题,请参阅Spring Security Reference:

疑难解答

当存储的密码之一没有“密码存储格式”一节中所述的 id 时,会发生以下错误。

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
     at org.springframework.security.crypto.password.DelegatingPasswordEncoder$UnmappedIdPasswordEncoder.matches(DelegatingPasswordEncoder.java:233)
     at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:196)

解决该错误的最简单方法是切换为明确提供您的密码编码所用的PasswordEncoder。解决它的最简单方法是找出您的密码当前是如何存储的,并明确提供正确的PasswordEncoder。如果您从 Spring Security 4.2.x 迁移,您可以通过公开 NoOpPasswordEncoder bean 恢复到以前的行为。例如,如果您使用的是 Java 配置,则可以创建如下所示的配置:

恢复到NoOpPasswordEncoder 被认为是不安全的。您应该改为使用 DelegatingPasswordEncoder 来支持安全密码编码。

@Bean
public static NoOpPasswordEncoder passwordEncoder() 
    return NoOpPasswordEncoder.getInstance();

如果您使用 XML 配置,您可以公开一个带有 id passwordEncoderPasswordEncoder

<b:bean id="passwordEncoder"
   class="org.springframework.security.crypto.NoOpPasswordEncoder" factory-method="getInstance"/>

或者,您可以在所有密码前加上正确的 ID,然后继续使用 DelegatingPasswordEncoder。例如,如果您使用 BCrypt,您可以从以下位置迁移您的密码:

$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

bcrypt$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG

【讨论】:

这里要详细说明确凿的证据是当您尝试在基本授权中使用明文客户端 ID 和明文密码在 /oauth/token 获取令牌时。修复是对支持 SQL 数据库中的现有客户端机密进行 Bcrypt。日志中的错误是Encoded password does not look like BCrypt,因为密码一开始就没有被编码为任何东西。【参考方案2】:

正如上面提到的@false_memories,使用 Spring Boot 2,您需要对您的秘密进行编码。在我的项目中,它看起来像:

public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
    String secretEncoded = passwordEncoder().encode("secret");
    clients.inMemory().withClient("some-web-app").secret(secretEncoded).accessTokenValiditySeconds(expiration)
            .scopes("read", "write").authorizedGrantTypes("password", "refresh_token").resourceIds("resource");

【讨论】:

【参考方案3】:

OAuth2 AuthorizationServer 使用基本身份验证。

因此,您还需要在 AuthorizationServerConfig 中使用 delegatedPasswordEncoder 对您的客户端密码进行编码,以彻底解决“没有为 id "null" 映射 PasswordEncoder ”异常。

姚刘的回答解决了我的问题。

1) 创建了一个 bean 来自动连接 PasswordEncoder;

@Bean
public PasswordEncoder passwordEncoder() 
    String idForEncode = "bcrypt";
    Map<String, PasswordEncoder> encoderMap = new HashMap<>();
    encoderMap.put(idForEncode, new BCryptPasswordEncoder());
    return new DelegatingPasswordEncoder(idForEncode, encoderMap);

2) AuthorizationServerConfig 类中的自动有线密码编码器;

@Autowired
private PasswordEncoder passwordEncoder;

3) 使用 passwordEncoder 对 CLIENT_SECRET 进行编码。

@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception 
    configurer
         .inMemory()
         .withClient(CLIENT_ID)
         .secret(passwordEncoder.encode(CLIENT_SECRET))
         .authorizedGrantTypes(GRANT_TYPE_FOR_LOGIN, GRANT_TYPE_FOR_REFRESH)
         .scopes(SCOPE_READ, SCOPE_WRITE)
         .accessTokenValiditySeconds(TOKEN_VALIDITY_SECONDS)
         .refreshTokenValiditySeconds(TOKEN_VALIDITY_SECONDS)
         .resourceIds(RESOURCES_IDS);

就是这样。

【讨论】:

【参考方案4】:

我想结束这个问题的循环。除了加密客户端机密。自 Spring OAuth 2.3.2 起,RedisTokenStore 问题也已得到解决:Spring OAuth 2.3.2

【讨论】:

以上是关于Spring Boot 2.0.0 + OAuth2的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Spring Boot 2.0.0 中自动装配身份验证管理器

Spring boot 集成Spring Security

Spring-boot 2.0.0 M1 - 执行器不工作

Spring Boot + Spring OAuth Java 配置

Spring Boot 和 OAuth2 社交登录,无法获取 refreshToken

使用 spring-boot-starter-oauth2-client 检索 OAuth2 3-legged 身份验证的访问令牌