本文共 7789 字,大约阅读时间需要 25 分钟。
本文对Spring Security OAuth2的token使用Redis保存,相比JWT实现的token存储,Redis可以随时吊销access_token,并且Redis响应速度很快,没有加密解密的过程
本文源代码在redis-token-saved模块中,仓库地址:
这里就不做测试了,仅做简记
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
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); }}
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/