OAuth2.0系列之信息Redis存储实践(七)

OAuth2.0系列之信息Redis存储教程(七)

      • 1、文章前言介绍
      • 2、典型例子实践
      • 3、功能简单测试

OAuth2.0系列博客:

  • OAuth2.0系列之基本概念和运作流程(一)
  • OAuth2.0系列之授权码模式实践教程(二)
  • OAuth2.0系列之简化模式实践教程(三)
  • OAuth2.0系列之密码模式实践教程(四)
  • OAuth2.0系列之客户端模式实践教程(五)
  • OAuth2.0系列之信息数据库存储教程(六)
  • OAuth2.0系列之信息Redis存储教程(七)
  • OAuth2.0系列之JWT令牌实践教程(八)
  • OAuth2.0系列之集成JWT实现单点登录

1、文章前言介绍

在前面文章中我们学习了OAuth2的一些基本概念,对OAuth2有了基本的认识,也对OAuth2.0的令牌、授权码等进行了jdbc方式的数据存储,接着本文再写一遍Redis版本的

IDEA中,Ctrl+Alt+B,可以看到TokenStore的实现,有如下几种:
OAuth2.0系列之信息Redis存储实践(七)_第1张图片
ok,其实对于token存储有如上方式,对于其它比如授权码code等的存储也基本如上几种,分别进行介绍:

  • InMemoryTokenStore,默认存储,保存在内存
  • JdbcTokenStore,access_token存储在数据库
  • JwtTokenStore,JWT这种方式比较特殊,这是一种无状态方式的存储,不进行内存、数据库存储,只是JWT中携带全面的用户信息,保存在jwt中携带过去校验就可以
  • RedisTokenStore,将 access_token 存到 redis 中。
  • JwkTokenStore,将 access_token 保存到 JSON Web Key。

ClientDetailsService的实现只有两种,并没有redis存储的:
OAuth2.0系列之信息Redis存储实践(七)_第2张图片

2、典型例子实践

实验环境准备:

  • IntelliJ IDEA
  • Maven3.+版本
    新建SpringBoot Initializer项目,可以命名oauth2-redis-store
    OAuth2.0系列之信息Redis存储实践(七)_第3张图片

OAuth2.0系列之信息Redis存储实践(七)_第4张图片
主要加入如下配置:

 <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
 
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-oauth2artifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-securityartifactId>
        dependency>

pom加入redis配置:

 <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-redisartifactId>
        dependency>

redis配置:

server.port=8888
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=

令牌存储配置:

  @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Bean
    TokenStore tokenStore() {
        return new RedisTokenStore(redisConnectionFactory);
    }

OAuth2.0配置类:

package com.example.springboot.oauth2.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

/**
 * 
 *  OAuth2.0配置类
 * 
* *
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2020/06/16 17:34  修改内容:
 * 
*/
@Configuration @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter { private static final String CLIENT_ID = "cms"; private static final String SECRET_CHAR_SEQUENCE = "{noop}secret"; private static final String SCOPE_READ = "read"; private static final String SCOPE_WRITE = "write"; private static final String TRUST = "trust"; private static final String USER ="user"; private static final String ALL = "all"; private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 2*60; private static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 2*60; // 密码模式授权模式 private static final String GRANT_TYPE_PASSWORD = "password"; //授权码模式 private static final String AUTHORIZATION_CODE = "authorization_code"; //refresh token模式 private static final String REFRESH_TOKEN = "refresh_token"; //简化授权模式 private static final String IMPLICIT = "implicit"; //指定哪些资源是需要授权验证的 private static final String RESOURCE_ID = "resource_id"; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Autowired RedisConnectionFactory redisConnectionFactory; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients // 使用内存存储 .inMemory() //标记客户端id .withClient(CLIENT_ID) //客户端安全码 .secret(SECRET_CHAR_SEQUENCE) //为true 直接自动授权成功返回code .autoApprove(true) .redirectUris("http://127.0.0.1:8084/cms/login") //重定向uri //允许授权范围 .scopes(ALL) //token 时间秒 .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS) //刷新token 时间 秒 .refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS) //允许授权类型 .authorizedGrantTypes(GRANT_TYPE_PASSWORD , AUTHORIZATION_CODE , REFRESH_TOKEN , IMPLICIT); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager) //支持获取token方式 .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST,HttpMethod.PUT,HttpMethod.DELETE,HttpMethod.OPTIONS) //刷新token .reuseRefreshTokens(true); } /** * 认证服务器的安全配置 * @param security * @throws Exception */ @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security // 开启/oauth/token_key验证端口认证权限访问 .tokenKeyAccess("isAuthenticated()") // 开启/oauth/check_token验证端口认证权限访问 .checkTokenAccess("isAuthenticated()") //允许表单认证 在授权码模式下会导致无法根据code获取token  .allowFormAuthenticationForClients(); } @Bean TokenStore tokenStore() { return new RedisTokenStore(redisConnectionFactory); } }

SpringSecurity配置:

package com.example.springboot.oauth2.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * 
 *      Spring Security配置类
 * 
* *
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2020/06/15 10:39  修改内容:
 * 
*/
@Configuration @EnableWebSecurity @Order(1) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //auth.inMemoryAuthentication() auth.inMemoryAuthentication() .withUser("nicky") .password("{noop}123") .roles("admin"); } @Override public void configure(WebSecurity web) throws Exception { //解决静态资源被拦截的问题 web.ignoring().antMatchers("/asserts/**"); web.ignoring().antMatchers("/favicon.ico"); } @Override protected void configure(HttpSecurity http) throws Exception { http // 配置登录页并允许访问 .formLogin().permitAll() // 配置Basic登录 //.and().httpBasic() // 配置登出页面 .and().logout().logoutUrl("/logout").logoutSuccessUrl("/") .and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll() // 其余所有请求全部需要鉴权认证 .anyRequest().authenticated() // 关闭跨域保护; .and().csrf().disable(); } }

3、功能简单测试

访问授权链接,在浏览器访问就可以,授权码模式response_type参数传code:
http://localhost:8888/oauth/authorize?client_id=cms&client_secret=secret&response_type=code

因为没登录,所以会返回SpringSecurity的默认登录页面,具体代码是http .formLogin().permitAll();,如果要弹窗登录的,可以配置http.httpBasic();,这种配置是没有登录页面的,自定义登录页面可以这样配置http.formLogin().loginPage("/login").permitAll()

如图,输入SpringSecurity配置的数据库密码
OAuth2.0系列之信息Redis存储实践(七)_第5张图片

登录成功,返回redirect_uri,拿到授权码

重定向回redirect_uri,http://localhost:8084/cms/login?code=???

配置一下请求头的授权参数,用Basic Auth方式,username即client_id,password即client_secret
OAuth2.0系列之信息Redis存储实践(七)_第6张图片

拿到授权码之后去获取token,本教程使用授权码方式
OAuth2.0系列之信息Redis存储实践(七)_第7张图片

OAuth2.0系列之信息Redis存储实践(七)_第8张图片

例子代码下载:code download

你可能感兴趣的:(OAuth2.0,spring,boot,redis,OAuth2.0,oauth,java)