• oauth2.0使用JWT存储token连接数据库


    创建项目

    在这里插入图片描述

    引入依赖

    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0modelVersion>
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-parentartifactId>
            <version>2.2.4.RELEASEversion>
            <relativePath/> 
        parent>
        <groupId>com.guyugroupId>
        <artifactId>guyu-jwt-authrozation-serverartifactId>
        <version>0.0.1-SNAPSHOTversion>
        <name>guyu-jwt-authrozation-servername>
        <description>Demo project for Spring Bootdescription>
        <properties>
            <java.version>1.8java.version>
        properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starterartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
                <scope>testscope>
            dependency>
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-oauth2artifactId>
                <version>2.1.4.RELEASEversion>
            dependency>
    
            <dependency>
                <groupId>mysqlgroupId>
                <artifactId>mysql-connector-javaartifactId>
                <scope>runtimescope>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-data-jpaartifactId>
            dependency>
    
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
                <scope>runtimescope>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <optional>trueoptional>
            dependency>
            <dependency>
                <groupId>org.springframework.securitygroupId>
                <artifactId>spring-security-testartifactId>
                <scope>testscope>
            dependency>
            <dependency>
                <groupId>org.junit.jupitergroupId>
                <artifactId>junit-jupiterartifactId>
                <version>RELEASEversion>
                <scope>testscope>
            dependency>
        dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-maven-pluginartifactId>
                plugin>
            plugins>
        build>
    
    project>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    编写配置文件application.yml

    server:
      servlet:
        context-path: /guyu
      port: 9000
    
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/oauth2?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&serverTimezone=Asia/Shanghai
        username: root
        password: 123456
      jpa:
        hibernate:
          ddl-auto: none
        show-sql: true
    
    security:
      oauth2:
        authorization:
          jwt:
            key-value: heartsuit
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    创建oauth_client_details表并插入数据

    1,创建表

    CREATE TABLE `oauth_client_details` (
      `client_id` varchar(128) NOT NULL COMMENT '客户端ID',
      `resource_ids` varchar(256) DEFAULT NULL COMMENT '资源ID集合,多个资源时用英文逗号分隔',
      `client_secret` varchar(256) DEFAULT NULL COMMENT '客户端密匙',
      `scope` varchar(256) DEFAULT NULL COMMENT '客户端申请的权限范围',
      `authorized_grant_types` varchar(256) DEFAULT NULL COMMENT '客户端支持的grant_type',
      `web_server_redirect_uri` varchar(256) DEFAULT NULL COMMENT '重定向URI',
      `authorities` varchar(256) DEFAULT NULL COMMENT '客户端所拥有的SpringSecurity的权限值,多个用英文逗号分隔',
      `access_token_validity` int(11) DEFAULT NULL COMMENT '访问令牌有效时间值(单位秒)',
      `refresh_token_validity` int(11) DEFAULT NULL COMMENT '更新令牌有效时间值(单位秒)',
      `additional_information` varchar(4096) DEFAULT NULL COMMENT '预留字段',
      `autoapprove` varchar(256) DEFAULT NULL COMMENT '用户是否自动Approval操作',
      PRIMARY KEY (`client_id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='客户端信息';
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2.插入数据
    client_secret的值是:secretApp

    INSERT INTO `oauth2`.`oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('clientApp', NULL, '$2a$10$5EbwX4rxq4w6rOlWJmd8kujWbmqdYQOzcpCEaXLqYb37lHHK.NGhK', 'all,read,write', 'authorization_code,client_credentials,implicit,password,refresh_token', 'http://www.baidu.com', NULL, 3600, 7200, NULL, 'false');
    
    
    • 1
    • 2

    编写代码

    1.创建认证服务器

    package com.guyu.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    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.ClientDetailsService;
    import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
    import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
    import org.springframework.security.oauth2.provider.token.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
    import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
    
    import javax.sql.DataSource;
    
    
    @Configuration
    @EnableAuthorizationServer //开启认证服务器
    public class CoustomAuthorizationConfig extends AuthorizationServerConfigurerAdapter {
    
        /**
         * springboot2.需要对密码加密
         * @return
         */
        @Bean
        public BCryptPasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
        //加载数据库
        @Autowired
        private DataSource dataSource;
    
        @Autowired
        private TokenStore tokenStore;
    
        @Autowired
        private DefaultTokenServices defaultTokenServices;
        // password 密码模式需要认证服务器中设置,中配置AuthenticationManager 否则报错:Unsupported grant
        @Autowired
        private AuthenticationManager authenticationManager;
    
    //    @Bean
    //    public TokenStore tokenStore(){
            return new InMemoryTokenStore();//基于内存存储token
    //        return new JdbcTokenStore(dataSource);//基于数据库
    //    }
    
        //客户端连接数据库
        @Bean
        public ClientDetailsService comstclientDetailsService(){
            return new JdbcClientDetailsService(dataSource);
        }
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            //注入连接数据库
            //oauth_client_details
            clients.withClientDetails(comstclientDetailsService());
        }
    
        @Override
         public void configure(AuthorizationServerSecurityConfigurer oauthServer){
            oauthServer.tokenKeyAccess("permitAll()")
                    .checkTokenAccess("isAuthenticated")//允许校验,oauth/check_token
                    .allowFormAuthenticationForClients();//允许申请表单提交,申请令牌
         }
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
            endpoints
                    .tokenStore(this.tokenStore)
                    .tokenServices(this.defaultTokenServices)
                    .authenticationManager(authenticationManager);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    2.创建Security登录配置

    package com.guyu.config;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    
    /**
     * Security登录配置
     */
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        @Autowired
        BCryptPasswordEncoder passwordEncoder;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("admin").password(passwordEncoder.encode("123456")).roles("ADMIN")
                    .and()
                    .withUser("user").password(passwordEncoder.encode("123456")).roles("USER");
        }
    
        /**
         * password 密码模式需要在认证服务器中设置 中配置AuthenticationManager
         * 否则报错:Unsupported grant type: password
         */
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    3.创建JWT生成token类 JWTTokenConfig

    package com.guyu.config;
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
    import org.springframework.security.oauth2.provider.token.TokenEnhancer;
    import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
    import org.springframework.security.oauth2.provider.token.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
    import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
    
    import java.util.Arrays;
    import java.util.concurrent.TimeUnit;
    
    @Configuration
    public class JWTTokenConfig {
        @Value("${security.oauth2.authorization.jwt.key-value}")
        private String secret;
    
        @Bean
        public TokenStore tokenStore() {
            return new JwtTokenStore(jwtAccessTokenConverter());
        }
    
        //DefaultTokenService中持有TokenStore接口用于保存token。用redis保存可使用redisTokenStore
        @Bean
        public DefaultTokenServices defaultTokenServices() {
            DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
            defaultTokenServices.setTokenStore(tokenStore());
            defaultTokenServices.setSupportRefreshToken(true);
    
            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
            tokenEnhancerChain.setTokenEnhancers(Arrays.asList(this.jwtTokenEnhancer(), this.jwtAccessTokenConverter()));
            defaultTokenServices.setTokenEnhancer(tokenEnhancerChain);
    
            defaultTokenServices.setAccessTokenValiditySeconds((int) TimeUnit.HOURS.toSeconds(1)); // 1小时
            return defaultTokenServices;
        }
    
        /**
         * 自定义的JwtAccessTokenConverter(把自己设置的jwt签名加入accessTokenConverter中)
         * @return
         */
    
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter() {
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
            converter.setSigningKey(secret);
            return converter;
        }
    
        @Bean
        public TokenEnhancer jwtTokenEnhancer() {
            return new JWTTokenEnhancer();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    4.自定义增强token

    package com.guyu.config;
    
    import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
    import org.springframework.security.oauth2.common.OAuth2AccessToken;
    import org.springframework.security.oauth2.provider.OAuth2Authentication;
    import org.springframework.security.oauth2.provider.token.TokenEnhancer;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * 自定义增强token
     */
    public class JWTTokenEnhancer implements TokenEnhancer {
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            Map<String, Object> additionalInfo = new HashMap<>();
            additionalInfo.put("hello", "world");
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            return accessToken;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    使用postman测试四种模式

    授权码模式

    1.获取授权码

    http://localhost:9000/guyu/oauth/authorize?client_id=clientApp&response_type=code
    
    • 1

    在这里插入图片描述

    2.第一次访问需要登录
    在这里插入图片描述
    3.同意授权
    在这里插入图片描述
    4.跳转到第三方服务获取授权码(百度)
    在这里插入图片描述
    5.使用postman获取access_token

    http://localhost:9000/guyu/oauth/token
    
    • 1

    在这里插入图片描述
    在这里插入图片描述
    6.获取刷新token

    http://localhost:9000/guyu/oauth/token
    
    • 1

    在这里插入图片描述
    7.JWT获取校验token

    密码模式

    1.JWT密码模式-获取token

    http://localhost:9000/guyu/oauth/token?client_id=clientApp&client_secret=secretApp&grant_type=password&password=123456&username=admin
    
    • 1

    在这里插入图片描述
    2.JWT密码模式-刷新token

    http://localhost:9000/guyu/oauth/token?client_id=clientApp&client_secret=secretApp&grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCIsInJlYWQiLCJ3cml0ZSJdLCJhdGkiOiJhNDdmNjdmNi1hYjA5LTQ2ZWItYWQwYy03ZDY4MzY5OTZhZTQiLCJoZWxsbyI6IndvcmxkIiwiZXhwIjoxNjY4NzAwMjU4LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6IjBlN2Q0NzUzLWI0ZTUtNDg2OS1hMDUwLWM2NjQ2YzMxNTQ1OCIsImNsaWVudF9pZCI6ImNsaWVudEFwcCJ9.FS0GrVH8RSI2_TjHxWuh8e8WokOa588XErDZ6EO7D1w
    
    • 1

    在这里插入图片描述

    客户端模式

    无刷新token
    在这里插入图片描述

    简化模式

    1.访问并登录

    http://localhost:9000/guyu/oauth/authorize?client_id=clientApp&response_type=token&scope=all&redirect_uri=http://www.baidu.com
    
    • 1

    在这里插入图片描述
    2.同意授权
    在这里插入图片描述
    3.得到access_token

    https://www.baidu.com/#access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJoZWxsbyI6IndvcmxkIiwiZXhwIjoxNjY2MTEyNDk1LCJhdXRob3JpdGllcyI6WyJST0xFX0FETUlOIl0sImp0aSI6ImYzOWE4NTUwLWQxZTMtNDc0MS1iNTEwLTQwMzEzYWUwNjA2NSIsImNsaWVudF9pZCI6ImNsaWVudEFwcCJ9.I6pAK_cpeTI_xyFeb9-MecgtC5VJ0M2yw5qYVlgqeDU&token_type=bearer&expires_in=3599&hello=world&jti=f39a8550-d1e3-4741-b510-40313ae06065
    
    • 1

    在这里插入图片描述

    解析JWTtoken

    https://tooltt.com/jwt-decode/
    可以分析token的头信息,加密类型,权限标识
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    【hexo博客配置】hexo icarus主题配置
    Vue源码用到了哪些设计模式
    RabbitMQ应用:利用Rabbitmq做一个日志小框架,实现自动日志入库功能。
    OpenDDS问题记录
    京东-黑客马拉松大赛复盘
    HW-小记(二)
    探索LightGBM:监督式聚类与异常检测
    HarmonyOS开发Java与ArkTS如何抉择
    linux下日志查看命令
    课程:压力管理
  • 原文地址:https://blog.csdn.net/shijinjins/article/details/127398900