博客
关于我
使用Redis作为Spring Security OAuth2的token存储
阅读量:418 次
发布时间:2019-03-06

本文共 7789 字,大约阅读时间需要 25 分钟。

写在前边

本文对Spring Security OAuth2的token使用Redis保存,相比JWT实现的token存储,Redis可以随时吊销access_token,并且Redis响应速度很快,没有加密解密的过程

本文源代码在redis-token-saved模块中,仓库地址:

这里就不做测试了,仅做简记

代码层级

Maven依赖

org.springframework.boot
spring-boot-starter-parent
2.2.1.RELEASE
org.springframework.security.oauth
spring-security-oauth2
2.4.0.RELEASE
org.springframework.boot
spring-boot-starter-data-redis
com.alibaba
fastjson
1.2.62

授权服务器保存token到Redis

application.yml

server:  port: 8080spring:  redis:    host: 127.0.0.1    port: 6379    password: 123    database: 0

AuthorizationConfig

@Configuration@EnableAuthorizationServerpublic class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {    /**     * redis工厂,默认使用lettue     */    @Autowired    public RedisConnectionFactory redisConnectionFactory;    /**     * 用户认证管理器     */    @Autowired    public AuthenticationManager authenticationManager;    /**     * 用户服务     */    @Autowired    public UserDetailsService userDetailsService;    /**     * 密码加密器     */    @Autowired    private PasswordEncoder passwordEncoder;    /**     * 授权服务安全配置,主要用于放行客户端访问授权服务接口     *     * @param security AuthorizationServerSecurityConfigurer     * @throws Exception 异常     */    @Override    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {        //允许客户端表单提交        security.allowFormAuthenticationForClients()                //客户端校验token访问许可                .checkTokenAccess("permitAll()")                //客户端token调用许可                .tokenKeyAccess("permitAll()");    }    /**     * 客户端信息配置,可配置多个客户端,这里可以使用配置文件进行代替     *     * @param clients 客户端设置     * @throws Exception 异常     */    @Override    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {        clients.inMemory()                .withClient("client-a")                .secret(passwordEncoder.encode("client-a-secret"))                .redirectUris("http://localhost:9001/callback")                //支持 授权码、密码两种授权模式,支持刷新token功能                .authorizedGrantTypes("authorization_code", "password", "refresh_token");    }    /**     * 配置端点     *     * @param endpoints 端点     * @throws Exception 异常     */    @Override    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {        //配置认证管理器        endpoints.authenticationManager(authenticationManager)                //配置用户服务                .userDetailsService(userDetailsService)                //配置token存储的服务与位置                .tokenServices(tokenService())                .tokenStore(tokenStore());    }    @Bean    public TokenStore tokenStore() {        //使用redis存储token        RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);        //设置redis token存储中的前缀        redisTokenStore.setPrefix("auth-token:");        return redisTokenStore;    }    @Bean    public DefaultTokenServices tokenService() {        DefaultTokenServices tokenServices = new DefaultTokenServices();        //配置token存储        tokenServices.setTokenStore(tokenStore());        //开启支持refresh_token,此处如果之前没有配置,启动服务后再配置重启服务,可能会导致不返回token的问题,解决方式:清除redis对应token存储        tokenServices.setSupportRefreshToken(true);        //复用refresh_token        tokenServices.setReuseRefreshToken(true);        //token有效期,设置12小时        tokenServices.setAccessTokenValiditySeconds(12 * 60 * 60);        //refresh_token有效期,设置一周        tokenServices.setRefreshTokenValiditySeconds(7 * 24 * 60 * 60);        return tokenServices;    }}

SecurityConfig

@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter {    @Bean    public PasswordEncoder passwordEncoder() {        return new BCryptPasswordEncoder();    }    /**     * 配置认证管理器信息,这里可以使用UserDetailsService实现类来提供用户信息,或Provider+UserDetailsService     *     * @param auth 认证管理器配置     * @throws Exception 异常     */    @Override    protected void configure(AuthenticationManagerBuilder auth) throws Exception {        //@formatter:off        auth.inMemoryAuthentication()                .withUser("hellxz")                .password(passwordEncoder().encode("test"))                .authorities(AuthorityUtils.createAuthorityList("all"));        //@formatter:on    }    /**     * 配置http访问控制     *     * @param http http安全配置     * @throws Exception 异常     */    @Override    protected void configure(HttpSecurity http) throws Exception {        http.authorizeRequests()                //放行options方法请求                .antMatchers(HttpMethod.OPTIONS).permitAll()                .anyRequest().authenticated()                .and()                .csrf().disable();    }    @Bean    public AuthenticationManager authenticationManager() throws Exception {        return super.authenticationManager();    }    @Bean    public UserDetailsService userDetailsService() {        return super.userDetailsService();    }}

启动类

/** * redis作为token存储的授权server */@SpringBootApplicationpublic class RedisAuthorizationServer {    public static void main(String[] args) {        SpringApplication.run(RedisAuthorizationServer.class, args);    }}

资源服务器访问Redis校验token配置

application.yml

server:  port: 8081spring:  redis:    host: 127.0.0.1    port: 6379    password: 123    database: 0

ResourceServerConfig

@Configuration@EnableResourceServerpublic class ResourceServerConfig extends ResourceServerConfigurerAdapter {    @Autowired    private RedisConnectionFactory redisConnectionFactory;    @Override    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {        //无状态        resources.stateless(true);        //设置token存储        resources.tokenStore(tokenStore());    }    /**     * 设置token存储,这一点配置要与授权服务器相一致     */    @Bean    public RedisTokenStore tokenStore(){        RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);        redisTokenStore.setPrefix("auth-token:");        return redisTokenStore;    }}

SecurityConfig

@Configuration@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter {    @Override    protected void configure(HttpSecurity http) throws Exception {        http.csrf().disable()                .authorizeRequests()                .anyRequest().authenticated()                .and()                .httpBasic();    }}

ResourceController

@RestControllerpublic class ResourceController {    private static final Logger log = LoggerFactory.getLogger(ResourceController.class);    @GetMapping("/user/{username}")    public UserVO user(@PathVariable String username){        log.info("{}", SecurityContextHolder.getContext().getAuthentication());        return new UserVO(username, username + "@foxmail.com");    }}

UserVO

package com.github.hellxz.oauth2.web.vo;public class UserVO {    private String username;    private String email;    public UserVO(String username, String email) {        this.username = username;        this.email = email;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getEmail() {        return email;    }    public void setEmail(String email) {        this.email = email;    }}

启动类

/** * 使用redis作为token存储的资源服务器,这里不使用调用授权服务器的方式去校验资源,只需要从redis中取token进行判断即可 */@SpringBootApplicationpublic class RedisResourceServer {    public static void main(String[] args) {        SpringApplication.run(RedisResourceServer.class, args);    }}

转载地址:http://uxauz.baihongyu.com/

你可能感兴趣的文章
C++ 函数重载
查看>>
使用mybatis-generator生成底层
查看>>
Mybatis【5】-- Mybatis多种增删改查那些你会了么?
查看>>
计算输入的一句英文语句中单词数
查看>>
lvs+keepalive构建高可用集群
查看>>
6 个 Linux 运维典型问题
查看>>
Failed to get D-Bus connection: Operation not permitted解决
查看>>
取消vim打开文件全是黄色方法
查看>>
一个系统部署多个tomcat实例
查看>>
HP服务器设置iLO
查看>>
从头实现一个WPF条形图
查看>>
使用QT实现一个简单的登陆对话框(纯代码实现C++)
查看>>
QT :warning LNK4042: 对象被多次指定;已忽略多余的指定
查看>>
GLFW 源码 下载-编译-使用/GLAD配置
查看>>
针对单个网站的渗透思路
查看>>
Typescript 学习笔记六:接口
查看>>
02、MySQL—数据库基本操作
查看>>
OpenJDK1.8.0 源码解析————HashMap的实现(一)
查看>>
MySQL-时区导致的时间前后端不一致
查看>>
2021-04-05阅读小笔记:局部性原理
查看>>