spring-security-oauth2 中 @EnableAuthorizationServer 使用数据库存储授权码,令牌等信息

业余杂谈 herman 2084浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

前面的文章,大家可能都注意到了,有一个问题。那就是 oauth_client 和 oauth_client_secret 都是写死的。在微信和 QQ 开发者授权登录的后台,没新注册一个应用,只需要做简单的配置一下即可。如果写死了,那么新来的应用怎么办?该配置吗?不现实吧。

所以在 spring-security-oauth2 中有一个 ClientDetailsServiceConfigurer,我们可以借助它设置一个数据源。把授权码,令牌,客户端信息等存入数据库。像我们上一章中用的 InMemory,应用已重启,就无法用了。

整个代码该动非常小,只需要在 OAuthAuthorizationConfig 中重写部分方法即可。

@Configuration  
@EnableAuthorizationServer  
static class OAuthAuthorizationConfig extends AuthorizationServerConfigurerAdapter {  
    @Autowired  
    private Environment env;
    @Bean  
    public DataSource dataSource() {  
        final DriverManagerDataSource dataSource = new DriverManagerDataSource();  
        dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));  
        dataSource.setUrl(env.getProperty("spring.datasource.url"));  
        dataSource.setUsername(env.getProperty("spring.datasource.username"));  
        dataSource.setPassword(env.getProperty("spring.datasource.password"));  
        return dataSource;  
    }  
    @Bean  
    public ApprovalStore approvalStore() {  
        return new JdbcApprovalStore(dataSource());  
    }  
    @Bean  
    protected AuthorizationCodeServices authorizationCodeServices() {  
        return new JdbcAuthorizationCodeServices(dataSource());  
    }  
    @Bean  
    public TokenStore tokenStore() {  
        return new JdbcTokenStore(dataSource());  
    }  
    @Override  
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {  
        clients.jdbc(dataSource()); // oauth_client_details  
    }  
    @Override  
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {  
        endpoints.approvalStore(approvalStore()) // oauth_approvals  
         .authorizationCodeServices(authorizationCodeServices())    // oauth_code  
         .tokenStore(tokenStore()); // oauth_access_token & oauth_refresh_token  
    }  
}  

pom.xml 中引入数据库驱动配置:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>  
    <groupId>org.springframework</groupId>  
    <artifactId>spring-jdbc</artifactId>  
</dependency>

application.yml 中的配置如下:

spring:
    datasource:
        host: 127.0.0.1
        port: 3306
        dbname: xttblog
        username: xttblog
        password: xttblog
        url: jdbc:mysql://${spring.datasource.host}:${spring.datasource.port}/${spring.datasource.dbname}?useUnicode=true&characterEncoding=UTF-8&useSSL=false
        initialSize: 1
        minIdle: 1
        maxActive: 4
        maxWait: 60000

有数据库就有数据表,这里总共涉及到 6 张表。SQL 如下:

CREATE TABLE oauth_access_token  
(  
  token_id character varying(256), -- MD5加密的access_token的值  
  token bytea, -- OAuth2AccessToken.java对象序列化后的二进制数据  
  authentication_id character varying(256), -- MD5加密过的username,client_id,scope  
  user_name character varying(256), -- 登录的用户名  
  client_id character varying(256), -- 客户端ID  
  authentication bytea, -- OAuth2Authentication.java对象序列化后的二进制数据  
  refresh_token character varying(256) -- MD5加密果的refresh_token的值  
);  
COMMENT ON COLUMN oauth_access_token.token_id IS 'MD5加密的access_token的值';  
COMMENT ON COLUMN oauth_access_token.token IS 'OAuth2AccessToken.java对象序列化后的二进制数据';  
COMMENT ON COLUMN oauth_access_token.authentication_id IS 'MD5加密过的username,client_id,scope';  
COMMENT ON COLUMN oauth_access_token.user_name IS '登录的用户名';  
COMMENT ON COLUMN oauth_access_token.client_id IS '客户端ID';  
COMMENT ON COLUMN oauth_access_token.authentication IS 'OAuth2Authentication.java对象序列化后的二进制数据';  
COMMENT ON COLUMN oauth_access_token.refresh_token IS 'MD5加密果的refresh_token的值';  
  
CREATE TABLE oauth_approvals  
(  
  userid character varying(256), -- 登录的用户名  
  clientid character varying(256), -- 客户端ID  
  scope character varying(256), -- 申请的权限  
  status character varying(10), -- 状态(Approve或Deny)  
  expiresat timestamp without time zone, -- 过期时间  
  lastmodifiedat timestamp without time zone -- 最终修改时间  
);  
COMMENT ON COLUMN oauth_approvals.userid IS '登录的用户名';  
COMMENT ON COLUMN oauth_approvals.clientid IS '客户端ID';  
COMMENT ON COLUMN oauth_approvals.scope IS '申请的权限';  
COMMENT ON COLUMN oauth_approvals.status IS '状态(Approve或Deny)';  
COMMENT ON COLUMN oauth_approvals.expiresat IS '过期时间';  
COMMENT ON COLUMN oauth_approvals.lastmodifiedat IS '最终修改时间';  
  
CREATE TABLE oauth_client_details  
(  
  client_id character varying(256) NOT NULL, -- 客户端ID  
  resource_ids character varying(256), -- 资源ID集合,多个资源时用逗号(,)分隔  
  client_secret character varying(256), -- 客户端密匙  
  scope character varying(256), -- 客户端申请的权限范围  
  authorized_grant_types character varying(256), -- 客户端支持的grant_type  
  web_server_redirect_uri character varying(256), -- 重定向URI  
  authorities character varying(256), -- 客户端所拥有的Spring Security的权限值,多个用逗号(,)分隔  
  access_token_validity integer, -- 访问令牌有效时间值(单位:秒)  
  refresh_token_validity integer, -- 更新令牌有效时间值(单位:秒)  
  additional_information character varying(4096), -- 预留字段  
  autoapprove character varying(256), -- 用户是否自动Approval操作  
  CONSTRAINT oauth_client_details_pkey PRIMARY KEY (client_id)  
);  
COMMENT ON COLUMN oauth_client_details.client_id IS '客户端ID';  
COMMENT ON COLUMN oauth_client_details.resource_ids IS '资源ID集合,多个资源时用逗号(,)分隔';  
COMMENT ON COLUMN oauth_client_details.client_secret IS '客户端密匙';  
COMMENT ON COLUMN oauth_client_details.scope IS '客户端申请的权限范围';  
COMMENT ON COLUMN oauth_client_details.authorized_grant_types IS '客户端支持的grant_type';  
COMMENT ON COLUMN oauth_client_details.web_server_redirect_uri IS '重定向URI';  
COMMENT ON COLUMN oauth_client_details.authorities IS '客户端所拥有的Spring Security的权限值,多个用逗号(,)分隔';  
COMMENT ON COLUMN oauth_client_details.access_token_validity IS '访问令牌有效时间值(单位:秒)';  
COMMENT ON COLUMN oauth_client_details.refresh_token_validity IS '更新令牌有效时间值(单位:秒)';  
COMMENT ON COLUMN oauth_client_details.additional_information IS '预留字段';  
COMMENT ON COLUMN oauth_client_details.autoapprove IS '用户是否自动Approval操作';  
  
CREATE TABLE oauth_client_token  
(  
  token_id character varying(256), -- MD5加密的access_token值  
  token bytea, -- OAuth2AccessToken.java对象序列化后的二进制数据  
  authentication_id character varying(256), -- MD5加密过的username,client_id,scope  
  user_name character varying(256), -- 登录的用户名  
  client_id character varying(256) -- 客户端ID  
);  
COMMENT ON COLUMN oauth_client_token.token_id IS 'MD5加密的access_token值';  
COMMENT ON COLUMN oauth_client_token.token IS 'OAuth2AccessToken.java对象序列化后的二进制数据';  
COMMENT ON COLUMN oauth_client_token.authentication_id IS 'MD5加密过的username,client_id,scope';  
COMMENT ON COLUMN oauth_client_token.user_name IS '登录的用户名';  
COMMENT ON COLUMN oauth_client_token.client_id IS '客户端ID';  
  
CREATE TABLE oauth_code  
(  
  code character varying(256), -- 授权码(未加密)  
  authentication bytea -- AuthorizationRequestHolder.java对象序列化后的二进制数据  
);  
COMMENT ON COLUMN oauth_code.code IS '授权码(未加密)';  
COMMENT ON COLUMN oauth_code.authentication IS 'AuthorizationRequestHolder.java对象序列化后的二进制数据';  
  
CREATE TABLE oauth_refresh_token  
(  
  token_id character varying(256), -- MD5加密过的refresh_token的值  
  token bytea, -- OAuth2RefreshToken.java对象序列化后的二进制数据  
  authentication bytea -- OAuth2Authentication.java对象序列化后的二进制数据  
);  
COMMENT ON COLUMN oauth_refresh_token.token_id IS 'MD5加密过的refresh_token的值';  
COMMENT ON COLUMN oauth_refresh_token.token IS 'OAuth2RefreshToken.java对象序列化后的二进制数据';  
COMMENT ON COLUMN oauth_refresh_token.authentication IS 'OAuth2Authentication.java对象序列化后的二进制数据';  

解释如下:

  • oauth_access_token:访问令牌
  • oauth_refresh_token:更新令牌
  • oauth_client_details:客户端信息
  • oauth_code:授权码
  • oauth_approvals:授权记录
  • oauth_client_token:这张表比较特殊,不用于 Provider,是客户端用的

我们先手动插入一条数据,就可以测试我们的授权功能了。

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 ('oauth_client', null, 'oauth_client_secret', 'read,write', 'authorization_code,refresh_token', 'http://www.xttblog.com', 'ROLE_USER', 1800, 86400, null, false);

参考资料

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加QQ1群:135430763(2000人群已满),QQ2群:454796847(已满),QQ3群:187424846(已满)。QQ群进群密码:xttblog,想加微信群的朋友,之前的微信号好友已满,请加博主新的微信号:xttblog,备注:“xttblog”,添加博主微信拉你进群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作可添加助理微信进行沟通!

本文原文出处:业余草: » spring-security-oauth2 中 @EnableAuthorizationServer 使用数据库存储授权码,令牌等信息