zoukankan      html  css  js  c++  java
  • OAuth2.0系列之信息Redis存储实践(七)

    @


    OAuth2.0系列博客:

    1、文章前言介绍

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

    IDEA中,Ctrl+Alt+B,可以看到TokenStore的实现,有如下几种:
    在这里插入图片描述
    ok,其实对于token存储有如上方式,对于其它比如授权码code等的存储也基本如上几种,分别进行介绍:

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

    ClientDetailsService的实现只有两种,并没有redis存储的:
    在这里插入图片描述

    2、典型例子实践

    实验环境准备:

    • IntelliJ IDEA
    • Maven3.+版本
      新建SpringBoot Initializer项目,可以命名oauth2-redis-store
      在这里插入图片描述

    在这里插入图片描述
    主要加入如下配置:

     <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
     <!-- Spring Cloud Oauth2-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-oauth2</artifactId>
            </dependency>
            <!-- Spring Cloud Security-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-security</artifactId>
            </dependency>
    

    pom加入redis配置:

     <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </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;
    
    /**
     * <pre>
     *  OAuth2.0配置类
     * </pre>
     *
     * <pre>
     * @author mazq
     * 修改记录
     *    修改后版本:     修改人:  修改日期: 2020/06/16 17:34  修改内容:
     * </pre>
     */
    @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;
    
    /**
     * <pre>
     *      Spring Security配置类
     * </pre>
     *
     * <pre>
     * @author mazq
     * 修改记录
     *    修改后版本:     修改人:  修改日期: 2020/06/15 10:39  修改内容:
     * </pre>
     */
    @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配置的数据库密码
    在这里插入图片描述

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

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

    配置一下请求头的授权参数,用Basic Auth方式,username即client_id,password即client_secret
    在这里插入图片描述

    拿到授权码之后去获取token,本教程使用授权码方式
    在这里插入图片描述

    在这里插入图片描述

    例子代码下载:code download

  • 相关阅读:
    java多线程编程核心技术——第七章补漏拾遗
    java多线程编程核心技术——第六章总结
    第六章:单例模式与多线程序言
    java多线程编程核心技术——第五章总结
    第五章——定时器Timer序言
    我的日志app企划书1.0版本
    du -sh
    安装saltstack使用的shell
    Neo4j社区版配置文件
    挂载磁盘
  • 原文地址:https://www.cnblogs.com/mzq123/p/13152459.html
Copyright © 2011-2022 走看看