使用Redis作为Spring Security OAuth2的token存储
写在前边
本文对Spring Security OAuth2的token使用Redis保存,相比JWT实现的token存储,Redis可以随时吊销access_token,并且Redis响应速度很快,没有加密解密的过程
本文源代码在redis-token-saved模块中,仓库地址:https://github.com/hellxz/spring-security-oauth2-learn
这里就不做测试了,仅做简记
代码层级
Maven依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <!-- Spring Security OAuth2 --> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.4.0.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency> </dependencies>
授权服务器保存token到Redis
application.yml
server: port: 8080 spring: redis: host: 127.0.0.1 port: 6379 password: 123 database: 0
AuthorizationConfig
@Configuration @EnableAuthorizationServer public 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 @EnableWebSecurity public 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 */ @SpringBootApplication public class RedisAuthorizationServer { public static void main(String[] args) { SpringApplication.run(RedisAuthorizationServer.class, args); } }
资源服务器访问Redis校验token配置
application.yml
server: port: 8081 spring: redis: host: 127.0.0.1 port: 6379 password: 123 database: 0
ResourceServerConfig
@Configuration @EnableResourceServer public 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 @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .authorizeRequests() .anyRequest().authenticated() .and() .httpBasic(); } }
ResourceController
@RestController public 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进行判断即可 */ @SpringBootApplication public class RedisResourceServer { public static void main(String[] args) { SpringApplication.run(RedisResourceServer.class, args); } }
本文作者:东北小狐狸
本文链接:https://www.cnblogs.com/hellxz/p/12044482.html
版权声明:本作品采用自由转载-非商用-非衍生-保持署名 (CC BY-NC-ND 3.0)许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步