0
点赞
收藏
分享

微信扫一扫

SpringSecurityOAuth2.0获取Token时报错Encoded password does not look like BCrypt


前言

**使用SpringSecurity OAuth时、认证服务器和资源服务器搭建完毕后,启动也没报错,然鹅问题还是有的!由于是在搭建阶段为了方便调试SpringSecurityOAuth2核心流程,也就是授权、认证这部分,所以刚开始客户端端点信息式存储在内存中的,但是实际开发中这些端点信息需要写入到数据库中的! **

内存中存储端点信息

SpringSecurityOAuth2.0获取Token时报错Encoded password does not look like BCrypt_spring


怎么输入账号密码都不行

SpringSecurityOAuth2.0获取Token时报错Encoded password does not look like BCrypt_数据库_02


异常如下

Encoded password does not look like BCrypt

SpringSecurityOAuth2.0获取Token时报错Encoded password does not look like BCrypt_spring_03


TMMD,这里就关系到版本问题,在SpringBoot1.X的时候认证服务配置如下即可

@Configuration
//@Order(99)
@EnableAuthorizationServer
public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("tao")
.secret("aaa")
.redirectUris("xxxxxx")
.scopes("all")
.authorizedGrantTypes("authorization_code","password");
}
}

但是现在升到SpringBoot2.X的时候就包这个问题 Encoded password does not look like BCrypt
那么就需要配置一下编码器
在@Configuration配置类下注入

@Bean
public PasswordEncoder passwordEncoder(){//密码加密
return new BCryptPasswordEncoder();
}

然后在认证服务器中添加编码规则

@Configuration
@EnableAuthorizationServer
public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
public PasswordEncoder passwordEncoder() {//密码加密
return new BCryptPasswordEncoder();
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("tao")
.secret(passwordEncoder().encode("aaa"))
.redirectUris("http://xx.sxxxx.xx/lxxive/pay/getCode.html")
.scopes("all")
.authorizedGrantTypes("authorization_code","password");
}

}

这里实际上就是将"aaa"做了passwordEncoder加密存储在内存中!这样确实解决了在内存中​​Encoded password does not look like BCrypt​​​异常问题!下面还没完,还有读取数据库中的端点信息报错!报错信息也是一样的​​Encoded password does not look like BCrypt​

数据库中存储端点信息

从内存中读取客户端端点信息切换到数据库中其实很简单,几步搞定

1.导入相关依赖

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>

2.添加对应yml配置

datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: xxxx
password: xxxxxx
url: jdbc:mysql://xxx.xxx.xxx.xxx/xx?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai

3.建库建表

DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
`client_id` varchar(255) NOT NULL COMMENT '客户端ID',
`resource_ids` varchar(255) DEFAULT NULL COMMENT '资源ID集合,多个资源时用逗号(,)分隔',
`client_secret` varchar(255) DEFAULT NULL COMMENT '客户端密匙',
`scope` varchar(255) DEFAULT NULL COMMENT '客户端申请的权限范围',
`authorized_grant_types` varchar(255) DEFAULT NULL COMMENT '客户端支持的grant_type',
`web_server_redirect_uri` varchar(255) DEFAULT NULL COMMENT '重定向URI',
`authorities` varchar(255) DEFAULT NULL COMMENT '客户端所拥有的Spring Security的权限值,多个用逗号(,)分隔',
`access_token_validity` int(11) DEFAULT NULL COMMENT '访问令牌有效时间值(单位:秒)',
`refresh_token_validity` int(11) DEFAULT NULL COMMENT '更新令牌有效时间值(单位:秒)',
`additional_information` varchar(255) DEFAULT NULL COMMENT '预留字段',
`autoapprove` varchar(255) DEFAULT NULL COMMENT '用户是否自动Approval操作,false时需要跳转到授权界面,true无需跳转'
PRIMARY KEY (`client_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='终端信息表';

提供两条测试数据

INSERT  INTO `oauth_client_details`(`client_id`,`resource_ids`,`client_secret`,`scope`,`authorized_grant_types`,`web_server_redirect_uri`,`authorities`,`access_token_validity`,`refresh_token_validity`,`additional_information`,`autoapprove`) 
VALUES
('app',NULL,'app','all','password,refresh_token,authorization_code,client_credentials','https://editor.cs.net/md/?articleId=109684318',NULL,NULL,NULL,NULL,'false'),
('tao',NULL,'$2a$10$HUYTaaKfdX2Jt7cxMU/rhunGD16d.xGRxmbF6BEQhdCXc5.Gwv.Du','all','password,refresh_token,authorization_code,client_credentials','https://editor.c.net/md/?articleId=109684318',NULL,NULL,NULL,NULL,'false'),

其他相关建表​​详情​​我这里目前只使用到这oauth_client_details张表,所以其他表不做扩展介绍了!

4.修改AuthorizationServerConfig代码
原有客户端端点信息配置

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

//内存中读取,方便服务搭建是测试
clients.inMemory()
.withClient("tao")
.secret(passwordEncoder().encode("secret"))
.resourceIds("product-id") //资源标识用来限制可以访问的资源服务标识
.redirectUris("http://47.111.238.83:8077/build/goRoomSearch?buildId=136")
.scopes("all")//允许的授权范围
.autoApprove(false)//false表示跳转到授权页面
.authorizedGrantTypes("authorization_code","password")
.and()
.withClient("client_2")
.resourceIds("yiyi")
.authorizedGrantTypes("password", "refresh_token")
.scopes("select")
.authorities("client")
.secret(passwordEncoder().encode("123456"))
}

修改为如下

@Bean
public ClientDetailsService clientDetails() {
ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
return clientDetailsService;
}

//配置端点信息
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetails());
}

或者直接写在一起

//配置端点信息
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
clients.withClientDetails(clientDetailsService );
}

5重启认证服务器
前面在数据库中插入两条端点记录,一条为app的另一条为tao的,我们先用app这个端点获取授权码,获取授权码是成功的,那么我们在通过授权码获取Token,那么这时还是会报同样的错​​​Encoded password does not look like BCrypt​​​,不要慌,这时我故意的是为了引出根本问题所在,我们切换端点获取授权码,使用tao这个端点获取授权码,然后通过授权码得到token,那么这里是可以的,注意tao这个端点的client_secret是加密的,原密码是secret,这里其实就和内存中将"aaa"做了passwordEncoder加密存储在内存中是一样的,问题的根源就在于SpringSecurityOAuth2.0版本升级后做了安全​​官方说明​​

6.问题解决

  1. 一般我们客户端账号密码不需要加密,所以在这里实现 .passwordEncoder(NoOpPasswordEncoder.getInstance())告诉security客户端密码不需要加密(这种方式我测试了一下,好像并没什么卵用,还是会报同样的错)

@Bean
public ClientDetailsService clientDetails() {
ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(NoOpPasswordEncoder.getInstance());
return clientDetailsService;
}

  1. 使用BCryptPasswordEncoder将数据库中client密码加密

System.out.println(new BCryptPasswordEncoder().encode("secret"));

第一种方式不通过分析一下,因为这里校验secret的逻辑是将客户端传入的和数据库中的secret解密后进行对比,所以第一种方式setPasswordEncoder只是更改编码方式,也就是数据库中的secret必须是编码后的数据


举报

相关推荐

0 条评论