OAuth2之第三方存储

导读:本篇文章讲解 OAuth2之第三方存储,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

OAuth2之第三方存储

令牌往哪里存?

在我们配置授权码模式的时候,有两个东西当时存在了内存中:

  • InMemoryAuthorizationCodeServices 这个表授权码存在内存中。
  • InMemoryTokenStore 表示生成的令牌存在内存中。

授权码用过一次就会失效,存在内存中没什么问题,但是令牌,我们实际上还有其他的存储方案。
我们所使用的 InMemoryTokenStore 实现了 TokenStore 接口,我们来看下 TokenStore 接口的实现类:
在这里插入图片描述
可以看到,我们有多种方式来存储 access_token。

  1. InMemoryTokenStore,这是我们之前使用的,也是系统默认的,就是将 access_token 存到内存中,单机应用这个没有问题,但是在分布式环境下不推荐。
  2. JdbcTokenStore,看名字就知道,这种方式令牌会被保存到数据中,这样就可以方便的和其他应用共享令牌信息。
  3. JwtTokenStore,这个其实不是存储,因为使用了 jwt 之后,在生成的 jwt 中就有用户的所有信息,服务端不需要保存,这也是无状态登录。
  4. RedisTokenStore,这个很明显就是将 access_token 存到 redis 中。
  5. JwkTokenStore,将 access_token 保存到 JSON Web Key。

虽然这里支持的方案比较多,但是我们常用的实际上主要是两个,RedisTokenStore 和 JwtTokenStore,JwtTokenStore 的比较复杂,我会在后面专门写文章来单独介绍,这里先来跟大家演示存入 RedisTokenStore。

首先我们启动一个 Redis 服务,然后给 auth-server 添加 Redis 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

依赖添加成功后,在 application.properties 中添加 redis 配置:

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=填自己密码,没有就不要这个

配置完成后,我们修改 TokenStore 的实例,如下:

@Configuration
public class AccessTokenConfig {
    @Autowired
    RedisConnectionFactory redisConnectionFactory;
    @Bean
    TokenStore tokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }
}

然后分别启动 auth-server、client-app 以及 user-server,走一遍第三方登录流程,然后我们发现,派发的 access_token 在 redis 中也有一份:
在这里插入图片描述
可以看到,数据都存到 Redis 中了,access_token 这个 key 在 Redis 中的有效期就是授权码的有效期。正是因为 Redis 中的这种过期机制,让它在存储 access_token 时具有天然的优势。

客户端信息入库

在前面的文章中,客户端信息我们是直接存储在内存中的,像下面这样:

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
            .withClient("javaboy")
            .secret(new BCryptPasswordEncoder().encode("123"))
            .resourceIds("res1")
            .authorizedGrantTypes("authorization_code","refresh_token")
            .scopes("all")
            .redirectUris("http://localhost:8082/index.html");
}

然而在实际项目中,这种方式并不可取,一来客户端信息在代码中写死了,以后不好维护,而来我们的客户端信息可能量非常大,都写在代码里那你的代码该有多长呀(想象一下有多少第三方应用接入了微信登录)~

所以我们要将客户端信息存入数据库中。

客户端信息入库涉及到的接口主要是 ClientDetailsService,这个接口主要有两个实现类,如下:
在这里插入图片描述
InMemoryClientDetailsService 就不多说了,这是存在内存中的。如果要存入数据库,很明显是 JdbcClientDetailsService,我们来大概看下 JdbcClientDetailsService 的源码,就能分析出数据库的结构了:

DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details` (
  `client_id` varchar(48) NOT NULL,
  `resource_ids` varchar(256) DEFAULT NULL,
  `client_secret` varchar(256) DEFAULT NULL,
  `scope` varchar(256) DEFAULT NULL,
  `authorized_grant_types` varchar(256) DEFAULT NULL,
  `web_server_redirect_uri` varchar(256) DEFAULT NULL,
  `authorities` varchar(256) DEFAULT NULL,
  `access_token_validity` int(11) DEFAULT NULL,
  `refresh_token_validity` int(11) DEFAULT NULL,
  `additional_information` varchar(4096) DEFAULT NULL,
  `autoapprove` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

接下来我们将一开始定义的客户端的关键信息存入数据库中,如下:
在这里插入图片描述
既然用到了数据库,依赖当然也要提供相应的支持,我们给 auth-server 添加如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency

然后在 application.properties 中配置一下数据库的连接信息:

spring.datasource.url=jdbc:mysql:///leotemp?useUnicode=true&characterEncoding=utf8&useSSL=true
spring.datasource.password=123456
spring.datasource.username=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.main.allow-bean-definition-overriding=true

这里的配置多了最后一条。这是因为我们一会要创建自己的 ClientDetailsService,而系统已经创建了 ClientDetailsService,加了最后一条就允许我们自己的实例覆盖系统默认的实例。

接下来,我们来提供自己的实例即可:

@Autowired
DataSource dataSource;
@Bean
ClientDetailsService clientDetailsService() {
    return new JdbcClientDetailsService(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.withClientDetails(clientDetailsService());
}

修改后的 AuthorizationServerTokenServices 实例如下:

@Bean
AuthorizationServerTokenServices tokenServices() {
    DefaultTokenServices services = new DefaultTokenServices();
    services.setClientDetailsService(clientDetailsService());
    services.setSupportRefreshToken(true);
    services.setTokenStore(tokenStore);
    return services;
}

ps:我在做的时候也遇到了401问题,和数据库配置的授权模式有关,它提示我没有配置password模式,但是我查看了数据库是有的,后来我把数据库的数据重新配了一下就好了!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/16402.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!