【Spring Security OAuth】--- 客户端信息+token信息 数据库(mysql/redis)存储


项目源码地址 https://github.com/nieandsun/security


动力往往来自身边人的优秀!!!


1 客户端+token信息存储配置方式1

先将客户端信息存储在内存(不是很好),token信息由存储在内存改为存到redis数据库(应该是挺好的一种方式)

1.1 代码实现

  • 资源服务器配置类和具体解释看如下代码:
package com.nrsc.security.app.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;

/**
 * @author : Sun Chuan
 * @date : 2019/10/11 22:25
 * Description:认证服务器
 */
@Configuration
@EnableAuthorizationServer
public class NrscAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    //对正在进行授权的用户进行认证+校验时需要用到
    @Autowired
    private UserDetailsService NRSCDetailsService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenStore redisTokenStore;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /***
     * 入口点相关配置  ---  token的生成,存储方式等在这里配置
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                //指定使用的TokenStore,tokenStore用来存取token,默认使用InMemoryTokenStore
                //这里使用redis存储token
                .tokenStore(redisTokenStore)
                //下面的配置主要用来指定"对正在进行授权的用户进行认证+校验"的类
                //在实现了AuthorizationServerConfigurerAdapter适配器类后,必须指定下面两项
                .authenticationManager(authenticationManager)
                .userDetailsService(NRSCDetailsService);
    }

    /***
     * 第三方客户端相关的配置在这里进行配置 ,之前我们在yml配置文件里对客户端进行过简单的配置
     * 在这里进行配置会覆盖yml中的配置
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //注意:可配置的内容不止下面几个
        clients.inMemory()
                    //设置client-id和client-secret,注意client-secret必须要进行加密处理
                    .withClient("test")
                    .secret(passwordEncoder.encode("test"))
                    //设置accessToken的过期时间
                    .accessTokenValiditySeconds(600)
                    //客户端可以进行认证的方式
                    .authorizedGrantTypes("refresh_token", "authorization_code", "password")
                    //客户端能请求的授权类型
                    .scopes("read,write")
                .and()
                    //指定另一个客户端
                    .withClient("nrsc")
                    .secret(passwordEncoder.encode("123456"))
                    .accessTokenValiditySeconds(1200)
                    .authorizedGrantTypes("refresh_token", "authorization_code", "password")
                    .accessTokenValiditySeconds(7200)
                    .refreshTokenValiditySeconds(2592000)
                    .scopes("all");
    }
}

上面代码中注入的UserDetailsService 和PasswordEncoder 之前就已经有了,AuthenticationManager 和TokenStore的配置如下:

  • 将AuthenticationManager注入spring容器
package com.nrsc.security.app.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author : Sun Chuan
 * @date : 2019/10/12 23:39
 * Description: 用户访问授权服务器时,认证+授权所需要的配置类
 */
@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService NRSCDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    /***
     * 构造AuthenticationManager --- 可选参数不止下面两个
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(NRSCDetailsService)
                .passwordEncoder(passwordEncoder);
    }

    /***
     * 真正将AuthenticationManager注入到spring容器
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /***
     * 可以像资源服务器一样进行配置,然后访问认证服务器时就会根据下面的配置进行认证+授权
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //security5+ 认证默认为表单了也就是http.formLogin()
        http.httpBasic();
    }
}
  • 将 TokenStore注入spring容器
package com.nrsc.security.app.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

/**
 * @author : Sun Chuan
 * @date : 2019/10/24 13:56
 * Description: TokenStore的实现类有5个,这里将RedisTokenStore注入spring容器
 */
@Configuration
public class TokenStoreConfig {

    /***
     * RedisTokenStore需要一个连接工厂,这里可以直接注入进来
     */
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    /***
     * 将RedisTokenStore注入到spring容器
     * @return
     */
    @Bean
    public TokenStore redisTokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }
}

1.2 测试

(1)以密码模式访问认证服务器进行认证请求,成功获得token
在这里插入图片描述
(2)redis库里已经存入了好些token的信息
在这里插入图片描述
(3)拿着生成的token访问用户信息接口可以访问到数据
在这里插入图片描述


2 将客户端信息保存到mysql( 推荐)

2.1 建表+代码开发

create table oauth_client_details (
  client_id VARCHAR(256) PRIMARY KEY,
  resource_ids VARCHAR(256),
  client_secret VARCHAR(256),
  scope VARCHAR(256),
  authorized_grant_types VARCHAR(256),
  web_server_redirect_uri VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additional_information VARCHAR(4096),
  autoapprove VARCHAR(256)
);
  • 数据库里做一些简单的配置
    在这里插入图片描述
  • 这样客户端的配置就由上面代码中的一坨变成了下面这样,且如果增加一个客户端或减少一个客户端并不用修改代码,直接删除或增加数据库里的一条数据就可以了
    /***
     * 第三方客户端相关的配置在这里进行配置 ,之前我们在yml配置文件里对客户端进行过简单的配置
     * 在这里进行配置会覆盖yml中的配置
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //直接将dataSource给clients就行了 --- jdbc会直接去库里拿客户端信息 
        clients.jdbc(dataSource);
    }

2.2 测试 — 同上


3 将token保存到mysql(不推荐放到mysql,推荐如1中放到redis)

3.1 建表+代码开发

create table oauth_client_token (
  token_id VARCHAR(256),
  token BLOB,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256)
);

create table oauth_access_token (
  token_id VARCHAR(256),
  token BLOB,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256),
  authentication BLOB,
  refresh_token VARCHAR(256)
);

create table oauth_refresh_token (
  token_id VARCHAR(256),
  token BLOB,
  authentication BLOB
);

create table oauth_code (
  code VARCHAR(256), authentication BLOB
);

create table oauth_approvals (
	userId VARCHAR(256),
	clientId VARCHAR(256),
	scope VARCHAR(256),
	status VARCHAR(10),
	expiresAt DATETIME,
	lastModifiedAt DATETIME
);
  • 配置JdbcTokenStore并利用JdbcTokenStore替换RedisTokenStore

注意: 这块代码我提交在了JdbcTokenStoreTest-2019/10/25这个分支上

    /***
     * 配置JdbcTokenStore
     * @return
     */
    @Bean
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }


    /***
     * 入口点相关配置  ---  token的生成,存储方式等在这里配置
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                //指定使用的TokenStore,tokenStore用来存取token,默认使用InMemoryTokenStore
                //这里使用redis存储token
                //.tokenStore(redisTokenStore)
                .tokenStore(tokenStore())  //使用JdbcTokenStore存储token
                //下面的配置主要用来指定"对正在进行授权的用户进行认证+校验"的类
                //在实现了AuthorizationServerConfigurerAdapter适配器类后,必须指定下面两项
                .authenticationManager(authenticationManager)
                .userDetailsService(NRSCDetailsService);
    }

2.2 测试

(1)以密码模式访问认证服务器进行认证请求,成功获得token — 同上
(2)mysql库里已经存入了好些token的信息
在这里插入图片描述
(3)拿着生成的token访问用户信息接口可以访问到数据 — 同上

发布了189 篇原创文章 · 获赞 187 · 访问量 39万+

猜你喜欢

转载自blog.csdn.net/nrsc272420199/article/details/102724087