Spring Security实现OAuth2协议及实战
作者:mmseoamin日期:2023-12-05

Spring Security实现OAuth2协议及实战

文章篇幅较长,愿读者耐心看完。如有不足之处,请指正。

一.OAuth2介绍

1.1 OAuth2是什么 怎么用

OAuth2是目前最流行的授权协议,用来授权第三方应用,获取用户数据。

举个例子:快递员想要进入小区,有3种方式。1是业主远程开门,2是业主告诉门禁密码,3是使用令牌(Oauth2)。

如图:

Spring Security实现OAuth2协议及实战,在这里插入图片描述,第1张

令牌和密码的区别:令牌相当于火车票,密码相当于是钥匙。

  • 令牌是短期的,自动失效。密码是长期有效。
  • 令牌是可以撤销的,撤销立即生效。密码一般不允许他们撤销。
  • 令牌有权限范围,如车票座位为10车A15座。密码一般是完整权限。

    第三方登录演示(网易云客户端利用QQ扫码登录)

    Spring Security实现OAuth2协议及实战,在这里插入图片描述,第2张

    网易云客使用QQ扫码登录中Oauth2协议各个角色扮演者

    • Rrsource Owner: 用户
    • Client: 网易云
    • Authorization Server: QQ
    • Resource Server: QQ
    • User Agent: 浏览器

      Oauth2.0与1.0的区别:

      • OAuth2.0有4种授权模式。优缺点:1.去掉签名,改用SSL(HTTPS)确保安全性。2.所有的token不再有对应的secret存在,签名过程简洁,这也直接导致OAuth2.0不能兼容老版本。3.能更好的支持不是基于浏览器的应用。4.OAuth2.0的访问令牌是"短命的",且可以刷新令牌。
      • OAuth1.0只有一种授权模式。优缺点:用的是http协议,申请RequestToken过程中,容易把攻击者调包。2.攻击者调包后的目的是为了仿造回调地址,拿到用户的accessToken。

        Oauth2授权模式:

        • 授权码模式:最完整和严谨的授权模式,第三方平台登录都是该模式。安全性最高。
        • 简化模式:省略授权码阶段,客户端是纯静态页面采用该模式。安全性高。
        • 密码模式:把用户名密码告诉客户端,对客户端高度信任,比如客户端和认证服务器是同一公司。安全性一般。
        • 客户端模式:直接因客户端名义申请令牌,很少有。安全性最差。
          1.2 为什么要用OAuth2

          Spring Security实现OAuth2协议及实战,在这里插入图片描述,第3张

          • cookie是不能跨域的,前后端分离分布式架构实现多系统SSO非常困难。
          • 移动端应用没有cookie,所以对于移动端支持不友好。
          • token基于header传递,部分解决了CSRF攻击。
          • token比sessionID大,客户端存储在Local Storage中,可以直接被JS读取。

            二.OAuth2实战

            2.1 搭建项目

            首先创建两个项目 一个是授权项目 一个是资源项目

            授权项目目录(java-skill-point)

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第4张

            pom.xml文件

            这里要注意springboot与springcloud的版本号

            
            
                4.0.0
                
                    org.springframework.boot
                    spring-boot-starter-parent
                    2.2.1.RELEASE
                     
                
                com.weige
                java-skill-point
                0.0.1-SNAPSHOT
                java-skill-point
                java-skill-point
                
                    1.8
                    Hoxton.SR5
                
                
                    
                    
                        org.springframework.boot
                        spring-boot-starter
                    
                    
                        org.springframework.boot
                        spring-boot-starter-test
                        test
                    
                    
                    
                        org.springframework.boot
                        spring-boot-starter-web
                    
                    
                    
                        org.projectlombok
                        lombok
                        1.18.22
                    
                    
                    
                        cn.hutool
                        hutool-all
                        5.7.20
                    
                    
                        org.springframework.cloud
                        spring-cloud-starter-oauth2
                    
                    
                        org.springframework.cloud
                        spring-cloud-starter-security
                    
                
                
                    
                        
                            org.springframework.cloud
                            spring-cloud-dependencies
                            ${spring-cloud.version}
                            pom
                            import
                        
                    
                
                
                    
                        
                            org.springframework.boot
                            spring-boot-maven-plugin
                        
                    
                
            
            

            application.yml文件

            server:
              port: 8888
            

            OAuth2Config文件

            package com.weige.javaskillpoint.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.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.InMemoryTokenStore;
            @Configuration
            @EnableAuthorizationServer
            public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
                @Autowired
                private AuthenticationManager authenticationManager;
                private static final String CLIENT_ID = "cms";
                private static final String SECRET_CHAR_SEQUENCE = "{noop}secret";
                private static final String ALL = "all";
                private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 30 * 60;
                // 密码模式授权模式
                private static final String GRANT_TYPE_PASSWORD = "password";
                //授权码模式
                private static final String AUTHORIZATION_CODE = "authorization_code";
                //简化授权模式
                private static final String IMPLICIT = "implicit";
                //客户端模式
                private static final String CLIENT_CREDENTIALS = "client_credentials";
                @Override
                public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
                    clients
                            .inMemory()
                            .withClient(CLIENT_ID)
                            .secret(SECRET_CHAR_SEQUENCE)
                            .autoApprove(false)
                            .redirectUris("http://127.0.0.1:8084/cms/login") //重定向uri
                            .scopes(ALL)
                            .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
                            .authorizedGrantTypes(AUTHORIZATION_CODE, IMPLICIT, GRANT_TYPE_PASSWORD, CLIENT_CREDENTIALS);
                }
                @Override
                public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
                    endpoints.authenticationManager(authenticationManager).tokenStore(memoryTokenStore());
                }
                /**
                 * 认证服务器的安全配置
                 *
                 * @param security
                 * @throws Exception
                 */
                @Override
                public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
                    security
                            //  开启/oauth/check_token验证端口认证权限访问,checkTokenAccess("isAuthenticated()")设置授权访问
                            .checkTokenAccess("permitAll()")
                            //允许表单认证
                            .allowFormAuthenticationForClients();
                }
                @Bean
                public TokenStore memoryTokenStore() {
                    return new InMemoryTokenStore();
                }
            }
            

            SecurityConfig文件

            package com.weige.javaskillpoint.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;
            @Configuration
            @EnableWebSecurity
            @Order(1)
            public class SecurityConfig extends WebSecurityConfigurerAdapter {
                @Override
                protected void configure(AuthenticationManagerBuilder auth) throws Exception {    //auth.inMemoryAuthentication()
                    auth.inMemoryAuthentication()
                            .withUser("lxs")
                            .password("{noop}123") //使用springsecurity5,需要加上{noop}指定使用NoOpPasswordEncoder给DelegatingPasswordEncoder去校验密码
                            .roles("admin");
                }
                @Override
                public void configure(WebSecurity web) throws Exception {
                    //解决静态资源被拦截的问题
            //        web.ignoring().antMatchers("/asserts/**");
                }
                @Override
                protected void configure(HttpSecurity http) throws Exception {
                    http
                            .formLogin().permitAll()
                            .and().logout().logoutUrl("/logout").logoutSuccessUrl("/")
                            .and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**", "/api/**").permitAll()
                            .anyRequest().authenticated()
                            // 关闭跨域保护;
                            .and().csrf().disable();
                }
                @Bean
                @Override
                public AuthenticationManager authenticationManagerBean() throws Exception {
                    return super.authenticationManagerBean();
                }
            }
            

            授权认证项目代码码完了 接下来给大家介绍代码的含义 重点是OAuth2Config与SecurityConfig两个类

            OAuth2Config代码介绍:

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第5张

            SecurityConfig代码介绍:

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第6张

            资源项目目录(oauth2-service-01)

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第7张

            pom.xml文件

            
            
                4.0.0
                
                    org.springframework.boot
                    spring-boot-starter-parent
                    2.2.1.RELEASE
                     
                
                com.weige
                java-skill-point
                0.0.1-SNAPSHOT
                java-skill-point
                java-skill-point
                
                    1.8
                    Hoxton.SR5
                
                
                    
                    
                        org.springframework.boot
                        spring-boot-starter
                    
                    
                        org.springframework.boot
                        spring-boot-starter-test
                        test
                    
                    
                    
                        org.springframework.boot
                        spring-boot-starter-web
                    
                    
                    
                        org.projectlombok
                        lombok
                        1.18.22
                    
                    
                    
                        cn.hutool
                        hutool-all
                        5.7.20
                    
                    
                        org.springframework.cloud
                        spring-cloud-starter-oauth2
                    
                    
                        org.springframework.cloud
                        spring-cloud-starter-security
                    
                
                
                    
                        
                            org.springframework.cloud
                            spring-cloud-dependencies
                            ${spring-cloud.version}
                            pom
                            import
                        
                    
                
                
                    
                        
                            org.springframework.boot
                            spring-boot-maven-plugin
                        
                    
                
            
            

            application.yml文件

            server:
              port: 8084
            

            Oauth2ResourceServerConfiguration文件

            package com.weige.javaskillpoint.config;
            import java.io.IOException;
            import javax.annotation.Resource;
            import org.springframework.context.annotation.Bean;
            import org.springframework.context.annotation.Configuration;
            import org.springframework.http.HttpStatus;
            import org.springframework.http.client.ClientHttpRequestFactory;
            import org.springframework.http.client.ClientHttpResponse;
            import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
            import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
            import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
            import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
            import org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter;
            import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
            import org.springframework.web.client.DefaultResponseErrorHandler;
            import org.springframework.web.client.RestTemplate;
            @Configuration
            @EnableResourceServer
            public class Oauth2ResourceServerConfiguration extends
                ResourceServerConfigurerAdapter {
              private static final String CHECK_TOKEN_URL = "http://localhost:8888/oauth/check_token";
              @Override
              public void configure(ResourceServerSecurityConfigurer resources) {
                RemoteTokenServices tokenService = new RemoteTokenServices();
                tokenService.setCheckTokenEndpointUrl(CHECK_TOKEN_URL);
                tokenService.setClientId("cms");
                tokenService.setClientSecret("secret");
                resources.tokenServices(tokenService);
              }
            }
            

            SecurityConfiguration文件

            package com.weige.javaskillpoint.config;
            import org.springframework.security.config.annotation.web.builders.HttpSecurity;
            import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
            import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
            @EnableWebSecurity
            public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
              @Override
              protected void configure(HttpSecurity http) throws Exception {
                http.authorizeRequests().antMatchers("/**").authenticated();
                // 禁用CSRF
                http.csrf().disable();
              }
            }
            

            HelloController文件

            package com.weige.javaskillpoint.controller;
            import org.springframework.security.access.annotation.Secured;
            import org.springframework.security.core.Authentication;
            import org.springframework.security.core.context.SecurityContextHolder;
            import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
            import org.springframework.web.bind.annotation.GetMapping;
            import org.springframework.web.bind.annotation.PutMapping;
            import org.springframework.web.bind.annotation.RequestMapping;
            import org.springframework.web.bind.annotation.RestController;
            import java.util.Arrays;
            @RestController
            @RequestMapping("/cms")
            public class HelloController {
                @GetMapping("/getCurrentUser")
                public Object getCurrentUser(Authentication authentication) {
                    return authentication;
                }
                @GetMapping("/index")
                public String index() {
                    return "index";
                }
                @PutMapping("/index2")
                public String index2() {
                    return "index2";
                }
            }
            

            资源项目代码码完了 接下来给大家介绍代码的含义 重点是Oauth2ResourceServerConfiguration与SecurityConfiguration两个类

            Oauth2ResourceServerConfiguration代码介绍:

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第8张

            SecurityConfiguration代码介绍:

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第9张

            HelloController类中定义了受限访问的资源

            2.2 启动两个项目 并进行接口测试

            启动授权服务项目,结果演示:

            测试:

            随便校验一个令牌:校验接口 http://localhost:8888/oauth/check_token?token=abcdefg123456

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第10张启动资源服务项目,访问接口:

            没有携带token,访问无权限

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第11张

            2.3 四种授权模式接口演示

            授权码模式:

            Spring Security实现OAuth2协议及实战,在这里插入图片描述,第12张

            1.申请授权码 localhost:8888/oauth/authorize?client_id=cms&cliect_secret=secret&response_type=code

            • client_id:客户端id,和授权配置类中设置的客户端id一致。
            • response_type:授权码模为code。
            • cliect_secret:客户端密码,和授权配置类中设置的secret一致。

              Spring Security实现OAuth2协议及实战,在这里插入图片描述,第13张

              Spring Security实现OAuth2协议及实战,在这里插入图片描述,第14张

              Spring Security实现OAuth2协议及实战,在这里插入图片描述,第15张

              Spring Security实现OAuth2协议及实战,在这里插入图片描述,第16张

              Spring Security实现OAuth2协议及实战,在这里插入图片描述,第17张

              2.根据授权码申请令牌(在PostMan中调用接口):http://localhost:8888/oauth/token?code=ckujfQ&grant_type=authorization_code&redirect_url=http://127.0.0.1:8084/cms/login&scope=all

              • grant_type:授权类型,填写authorization_code,表示授权码模式。
              • code:授权码,注意授权码使用一次就无效了,需要重新申请。
              • redirect_uri:跳转uri,当授权码申请成功后会跳转到此地址,并在后边带上code参数,这里需要。

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第18张

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第19张

                令牌校验:http://localhost:8888/oauth/check_token?token=4a7e8dbc-24ef-4517-8de3-d9b0229dfa0b

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第20张

                使用令牌:http://localhost:8888/oauth/check_token?token=4a7e8dbc-24ef-4517-8de3-d9b0229dfa0b

                携带token则访问资源项目接口成功

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第21张

                简化模式:

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第22张

                申请令牌 浏览器请求:localhost:8888/oauth/authorize?client_id=cms&redirect_uri=http://127.0.0.1:8084/cms/login&response_type=token&scope=all

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第23张

                输入网址回车

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第24张Spring Security实现OAuth2协议及实战,在这里插入图片描述,第15张

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第26张校验令牌:http://localhost:8888/oauth/check_token?token=f9013048-946b-4875-a83a-69371e7e0829

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第27张

                资源测试

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第28张

                密码模式:

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第29张

                申请令牌 使用PostMan:localhost:8888/oauth/token?grant_type=password&username=lxs&password=123&scope=all

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第30张

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第31张

                校验令牌:http://localhost:8888/oauth/check_token?token=1365345d-8765-47d4-8d2f-563a31a8b3a7

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第32张

                资源测试

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第33张

                客户端模式:

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第34张

                申请令牌 使用PostMan:localhost:8888/oauth/token?grant_type=password&username=lxs&password=123&scope=all

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第35张

                校验令牌:http://localhost:8888/oauth/check_token?token=5c58a1ef-e1d5-49e7-9ef7-da1063261998

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第36张

                资源测试

                Spring Security实现OAuth2协议及实战,在这里插入图片描述,第37张

                三.Spring Security实现OAuth2协议实战(对标大厂)

                3.1 生成JWT公钥私钥

                1. ⽣成密钥证书 下边命令⽣成密钥证书,采⽤RSA 算法每个证书包含公钥和私钥 创建⼀个⽂件夹,在该⽂件夹下执⾏如下命令⾏:

                keytool -genkeypair -alias kaikeba -keyalg RSA -keypass kaikeba -keystore kaikeba.jks -storepass kaikeb
                

                参数解释:

                • alias:密钥的别名
                • keyalg:使⽤的hash算法
                • keypass:密钥的访问密码
                • keystore:密钥库⽂件名
                • storepass:密钥库的访问密码

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第38张

                  导出公钥

                  下载网址 https://slproweb.com/products/Win32OpenSSL.html

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第39张

                  配置环境变量

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第40张

                  cmd进⼊kaikeba.jks⽂件所在⽬录执⾏如下命令 keytool -list -rfc --keystore kaikeba.jks | openssl x509 -inform pem -pubkey

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第41张

                  下⾯段内容是公钥

                  -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAojlMgqf4RVL0ExMpJWoO q35eow0lhDFTpUOUkU1ZGWoK+ZwQFUnR5w5U+u2mHqq3dFJWUIAmQC+y5p2ClsvG TbAvYQmL1k4X6oaGj7Bi9SSX6QQeM5bXsrXsjsGJyQyIbqgyBYIg4ZNB29UDcTCv xdFl8+rXoOppqENnTZpij8EIzJooCfrc2GzAeljmgPi4DFJnDAxE4joVz70xWk36 noRHSEfvmUaW+1S1T0cEH+j9p8PUGonnjqU8R6ZPmKAhU1w2t002dLqtkFDzxPW7 M1uJ4hq/CL7smvkOkGb0UVLAwFR9hzO2loxn/y0DcRdyxb5FVPQXnjXCp2hyT0mX pwIDAQAB -----END PUBLIC KEY-----

                  创建public.key文件 将公钥复制进去

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第42张

                  3.2 搭建授权项目与资源项目

                  搭建授权项目 项目目录

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第43张

                  pom.xml

                  
                  
                      4.0.0
                      
                          org.springframework.boot
                          spring-boot-starter-parent
                          2.2.1.RELEASE
                           
                      
                      com.weige
                      java-skill-point
                      0.0.1-SNAPSHOT
                      java-skill-point
                      java-skill-point
                      
                          1.8
                          Hoxton.SR5
                      
                      
                          
                          
                              org.springframework.boot
                              spring-boot-starter
                          
                          
                              org.springframework.boot
                              spring-boot-starter-test
                              test
                          
                          
                          
                              org.springframework.boot
                              spring-boot-starter-web
                          
                          
                          
                              org.projectlombok
                              lombok
                              1.18.22
                          
                          
                          
                              mysql
                              mysql-connector-java
                              runtime
                          
                          
                          
                              org.mybatis
                              mybatis
                              3.4.6
                          
                          
                          
                              org.mybatis.spring.boot
                              mybatis-spring-boot-starter
                              2.2.2
                          
                          
                          
                              cn.hutool
                              hutool-all
                              5.7.20
                          
                          
                              org.apache.commons
                              commons-lang3
                              3.7
                          
                          
                              org.springframework.cloud
                              spring-cloud-starter-oauth2
                          
                          
                              org.springframework.cloud
                              spring-cloud-starter-security
                          
                      
                      
                          
                              
                                  org.springframework.cloud
                                  spring-cloud-dependencies
                                  ${spring-cloud.version}
                                  pom
                                  import
                              
                          
                      
                      
                          
                              
                                  org.springframework.boot
                                  spring-boot-maven-plugin
                              
                          
                      
                  
                  

                  application.yml

                  server:
                    port: 8888
                  spring:
                    main:
                      allow-bean-definition-overriding: true
                    # mysql连接信息
                    datasource:
                      # mysql8之后
                      driver-class-name: com.mysql.cj.jdbc.Driver
                      url: jdbc:mysql://43.143.132.109:3306/index?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
                      username: root
                      password: ******
                  

                  大家在这里要创建对应的数据库index 并创建oauth_client_details表

                  CREATE TABLE `oauth_client_details` (
                    `client_id` varchar(256) COLLATE utf8mb4_german2_ci NOT NULL,
                    `resource_ids` varchar(256) COLLATE utf8mb4_german2_ci DEFAULT NULL,
                    `client_secret` varchar(256) COLLATE utf8mb4_german2_ci DEFAULT NULL,
                    `scope` varchar(256) COLLATE utf8mb4_german2_ci DEFAULT NULL,
                    `authorized_grant_types` varchar(256) COLLATE utf8mb4_german2_ci DEFAULT NULL,
                    `web_server_redirect_uri` varchar(256) COLLATE utf8mb4_german2_ci DEFAULT NULL,
                    `authorities` varchar(256) COLLATE utf8mb4_german2_ci DEFAULT NULL,
                    `access_token_validity` int(11) DEFAULT NULL,
                    `refresh_token_validity` int(11) DEFAULT NULL,
                    `additional_information` varchar(4096) COLLATE utf8mb4_german2_ci DEFAULT NULL,
                    `autoapprove` varchar(256) COLLATE utf8mb4_german2_ci DEFAULT NULL,
                    PRIMARY KEY (`client_id`)
                  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_german2_ci;
                  INSERT INTO `index`.`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 ('cms', '', 'a$WZQaLHfS6amrJzN50wE3e.upn8KIi1wmCH9FSdZE6OBt8OKSyGLm.', 'read, write', 'client_credentials,implicit,authorization_code,refresh_token,password', 'http://www.baidu.com', NULL, NULL, NULL, NULL, 'false');
                  ## 'a$WZQaLHfS6amrJzN50wE3e.upn8KIi1wmCH9FSdZE6OBt8OKSyGLm.' 是加密过后的123456
                  

                  AdminTokenConstant文件

                  package com.weige.javaskillpoint.config;
                  public class AdminTokenConstant {
                      /**
                       * 秘钥全名称
                       */
                      public static final String KEY_LOCATION = "kaikeba.jks";
                      /**
                       * 密钥的密码,此密码和别名要匹配
                       */
                      public static final String KEY_PASSWORD = "kaikeba";
                  }
                  

                  AuthorizationServerConfiguration文件

                  package com.weige.javaskillpoint.config;
                  import org.springframework.context.annotation.Bean;
                  import org.springframework.context.annotation.Configuration;
                  import org.springframework.core.io.ClassPathResource;
                  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.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.JwtAccessTokenConverter;
                  import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
                  import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
                  import javax.annotation.Resource;
                  import javax.sql.DataSource;
                  import java.util.concurrent.TimeUnit;
                  @Configuration
                  @EnableAuthorizationServer
                  public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
                      @Resource
                      private AuthenticationManager authenticationManager;
                      @Resource
                      private DataSource dataSource;
                      @Bean
                      public TokenStore tokenStore() {
                          return new JwtTokenStore(jwtAccessTokenConverter());
                      }
                      @Bean
                      public JwtAccessTokenConverter jwtAccessTokenConverter() {
                          // 证书路径和密钥库密码
                          KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(AdminTokenConstant.KEY_LOCATION), AdminTokenConstant.KEY_PASSWORD.toCharArray());
                          JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
                          // 密钥别名
                          converter.setKeyPair(keyStoreKeyFactory.getKeyPair(AdminTokenConstant.KEY_PASSWORD));
                          return converter;
                      }
                      /**
                       * 声明 ClientDetails实现
                       *
                       * @return
                       */
                      @Bean
                      public ClientDetailsService clientDetailsService() {
                          return new JdbcClientDetailsService(dataSource);
                      }
                      /**
                       * 配置客户端详情服务(ClientDetailsService),客户端详情信息在这里进行初始化,
                       * 你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息
                       *
                       * @param clients
                       * @throws Exception
                       */
                      @Override
                      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
                          // 直接读取数据库,需要保证数据库配置有客户端信息(oauth_client_details),否则资源服务器无法获取认证数据
                          clients.withClientDetails(clientDetailsService());
                      }
                      /**
                       * 配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services),还有token的存储方式(tokenStore)
                       *
                       * @param endpoints
                       */
                      @Override
                      public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
                          endpoints.tokenStore(tokenStore()).tokenEnhancer(jwtAccessTokenConverter()).authenticationManager(authenticationManager);
                          // 配置tokenServices参数
                          DefaultTokenServices tokenServices = new DefaultTokenServices();
                          tokenServices.setTokenStore(endpoints.getTokenStore());
                          tokenServices.setSupportRefreshToken(false);
                          tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
                          tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
                          tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30));
                          endpoints.tokenServices(tokenServices);
                      }
                      @Override
                      public void configure(AuthorizationServerSecurityConfigurer security) {
                          // 允许表单认证
                          security.allowFormAuthenticationForClients()
                                  // 开启/oauth/token_key验证端口无权限访问
                                  .tokenKeyAccess("permitAll()")
                                  // 开启/oauth/check_token验证端口认证权限访问
                                  .checkTokenAccess("permitAll()");
                      }
                  }
                  

                  SecurityConfiguration文件

                  package com.weige.javaskillpoint.config;
                  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.builders.HttpSecurity;
                  import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
                  import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
                  import org.springframework.security.core.userdetails.UserDetailsService;
                  import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
                  import org.springframework.security.crypto.password.PasswordEncoder;
                  import javax.annotation.Resource;
                  @Configuration
                  @EnableWebSecurity
                  public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
                      @Resource
                      private UserDetailsService userDetailsService;
                      @Bean
                      public PasswordEncoder passwordEncoder() {
                          return new BCryptPasswordEncoder();
                      }
                      @Override
                      @Bean
                      public AuthenticationManager authenticationManagerBean() throws Exception {
                          return super.authenticationManagerBean();
                      }
                      /**
                       * @param http
                       * @throws Exception
                       */
                      @Override
                      protected void configure(HttpSecurity http) throws Exception {
                          // 所有请求都加入HttpSecurity(多个HttpSecurity过滤)
                          http.requestMatchers().anyRequest()
                                  // 开放/oauth/开头的所有请求
                                  .and().authorizeRequests().antMatchers("/oauth/**").permitAll();
                      }
                      @Override
                      protected void configure(AuthenticationManagerBuilder auth) throws Exception {
                          // 注入自定义的UserDetailsService,采用BCrypt加密
                          auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
                      }
                  }
                  

                  UserDetailServiceImpl文件

                  package com.weige.javaskillpoint.service.impl;
                  import lombok.extern.slf4j.Slf4j;
                  import org.springframework.security.core.GrantedAuthority;
                  import org.springframework.security.core.authority.SimpleGrantedAuthority;
                  import org.springframework.security.core.userdetails.User;
                  import org.springframework.security.core.userdetails.UserDetails;
                  import org.springframework.security.core.userdetails.UserDetailsService;
                  import org.springframework.security.core.userdetails.UsernameNotFoundException;
                  import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
                  import org.springframework.stereotype.Service;
                  import org.apache.commons.lang3.StringUtils;
                  import java.util.ArrayList;
                  import java.util.HashMap;
                  import java.util.List;
                  import java.util.Map;
                  @Slf4j
                  @Service
                  public class UserDetailServiceImpl implements UserDetailsService {
                      /**
                       * 根据用户名加载用户信息
                       *
                       * @param username 用户名
                       * @return 用户详情
                       * @throws UsernameNotFoundException
                       */
                      @Override
                      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                          // 这里可以连接数据库 我这里写假数据
                          // 有两个用户(username:user,password:user;username:admin,password:admin)
                          Map map = new HashMap<>();
                          map.put("user", "USER");
                          map.put("admin", "ADMIN");
                          String passWord = "$2a$10$b7cqpfkMLYE2H5wxMluGQOrXo76ZfaAALEaemrfFLwDvvHuJuvX/2";
                          if (username.equals("admin")) {
                              passWord = "$2a$10$b7cqpfkMLYE2H5wxMluGQOrXo76ZfaAALEaemrfFLwDvvHuJuvX/2";
                          }
                          List grantedAuthorities = new ArrayList<>();
                          // 获取用户的授权
                          String s = map.get(username);
                          // Spring Security 中权限名称必须满足ROLE_XXX
                          GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(StringUtils.join("ROLE_", s));
                          grantedAuthorities.add(grantedAuthority);
                          log.info("granted authorities :{} ", grantedAuthorities);
                          return new User(username, passWord, grantedAuthorities);
                      }
                  }
                  

                  JavaSkillPointApplication文件

                  package com.weige.javaskillpoint;
                  import org.mybatis.spring.annotation.MapperScan;
                  import org.springframework.boot.SpringApplication;
                  import org.springframework.boot.autoconfigure.SpringBootApplication;
                  @SpringBootApplication
                  @MapperScan("com.weige.javaskillpoint.dao")
                  public class JavaSkillPointApplication {
                      public static void main(String[] args) {
                          SpringApplication.run(JavaSkillPointApplication.class, args);
                      }
                  }
                  

                  JavaSkillPointApplicationTests测试文件

                  package com.weige.javaskillpoint;
                  import com.fasterxml.jackson.databind.ObjectMapper;
                  import org.junit.jupiter.api.Test;
                  import org.springframework.boot.test.context.SpringBootTest;
                  import org.springframework.core.io.ClassPathResource;
                  import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
                  import org.springframework.security.jwt.Jwt;
                  import org.springframework.security.jwt.JwtHelper;
                  import org.springframework.security.jwt.crypto.sign.RsaSigner;
                  import org.springframework.security.jwt.crypto.sign.RsaVerifier;
                  import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
                  import java.security.KeyPair;
                  import java.security.interfaces.RSAPrivateKey;
                  import java.util.HashMap;
                  import java.util.Map;
                  @SpringBootTest
                  class JavaSkillPointApplicationTests {
                      @Test
                      public void testCreateJwt() throws Exception {
                          //证书⽂件
                          String key_location = "kaikeba.jks";
                          // 密钥库密码
                          String keystore_password = "kaikeba";
                          // 访问证书路径
                          ClassPathResource resource = new ClassPathResource(key_location);
                          // 密钥⼯⼚
                          KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resource, keystore_password.toCharArray());
                          // 密钥的密码,此密码和别名要匹配
                          String keypassword = "kaikeba";
                          //密钥别名
                          String alias = "kaikeba";
                          // 密钥对(密钥和公钥)
                          KeyPair keyPair = keyStoreKeyFactory.getKeyPair(alias, keypassword.toCharArray());
                          // 私钥
                          RSAPrivateKey aPrivate = (RSAPrivateKey) keyPair.getPrivate();
                          // 定义payload信息
                          Map tokenMap = new HashMap();
                          tokenMap.put("id", "123");
                          tokenMap.put("name", "malong");
                          tokenMap.put("roles", "r01,r02");
                          tokenMap.put("ext", "1");
                          // ⽣成jwt令牌
                          Jwt jwt = JwtHelper.encode(new ObjectMapper().writeValueAsString(tokenMap), new RsaSigner(aPrivate));
                          // 取出jwt令牌
                          String token = jwt.getEncoded();
                          System.out.println(token);
                      }
                      @Test
                      public void testVerify() {
                          //jwt令牌
                          String token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHQiOiIxIiwicm9sZXMiOiJyMDEscjAyIiwibmFtZSI6Im1hbG9uZyIsImlkIjoiMTIzIn0.X68eLdVW69xJQGcICVZapWUay-vs5Fkv0cYRQoymuagR95G4bOkJ4d3rer6ko9gMS55htLmAmv3HkzeCOOE4R6fXJcGzyuDWY9D9lC7ca0-AX4okS4iLeTQAf53AIDLM3d1DQbRdJYrdDbSwhXZXIaaaaQNiVpnN3kGXK6YB7f1ohlEURFT50bf7lKVyc8xoJX4-ojLfZiWP2C8Ov84yEOc-Q2t9kRwPtPqQjial69b0FmPqtdfPbhJG66NAQdikRCxqHKSgb6QSMc9AF9AV4RluaPixoGIpufouWpWXyk9PvK-QJwwUJgM11emDTX2wv8lf5VXH-Wdg_1Jc_uwjLA";
                          String publickey = "-----BEGIN PUBLIC KEY-----\n" +
                                  "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlym6EoAWxPYpTQHuWfqn\n" +
                                  "WqRkiUDrD+CyXM3Rzgtfi6ofudPDyEY5JbFcKIcfwjdQo+VLF0dIvyJA2csHhQIS\n" +
                                  "vZBspsE9cjz24GOuYSYufYtwOVcbjsvZ3JQaJahR6rBXzPTjvaiu1KtFtEJavWQ8\n" +
                                  "S9nhZ4MEMImW8r+Qphd0R4OB8KHrWoztYNznWpSaaH3QB446tQyyBre7tEPp3E6J\n" +
                                  "Xq+ApI5UKBpTdHW7b7MSJW836sYm8g5XfaXF667rlkdS03q3B182hUcghRY+fAyS\n" +
                                  "OtD2A0ib7XlrNADPL9X3dazWCYTnbNDswiqfpoDrbLy0PWFeIq09amL+E1ivKJZS\n" +
                                  "9wIDAQAB\n" +
                                  "-----END PUBLIC KEY-----";
                          //校验jwt
                          Jwt jwt = JwtHelper.decodeAndVerify(token, new RsaVerifier(publickey));
                          //获取jwt原始内容
                          String claims = jwt.getClaims();
                          System.out.println(claims);
                      }
                      @Test
                      public void getEnPassword(){
                          String encode = new BCryptPasswordEncoder().encode("123456");
                          System.out.println(encode);
                      }
                  }
                  

                  这里别忘记了生成的JWT公钥私钥文件 放到reources目录下即可

                  搭建资源项目 项目目录

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第44张

                  pom.xml

                  
                  
                      4.0.0
                      
                          org.springframework.boot
                          spring-boot-starter-parent
                          2.2.1.RELEASE
                           
                      
                      com.weige
                      java-skill-point
                      0.0.1-SNAPSHOT
                      java-skill-point
                      java-skill-point
                      
                          1.8
                          Hoxton.SR5
                      
                      
                          
                          
                              org.springframework.boot
                              spring-boot-starter
                          
                          
                              org.springframework.boot
                              spring-boot-starter-test
                              test
                          
                          
                          
                              org.springframework.boot
                              spring-boot-starter-web
                          
                          
                          
                              org.projectlombok
                              lombok
                              1.18.22
                          
                          
                              org.apache.commons
                              commons-lang3
                              3.7
                          
                          
                          
                              mysql
                              mysql-connector-java
                              runtime
                          
                          
                          
                              org.mybatis
                              mybatis
                              3.4.6
                          
                          
                          
                              org.mybatis.spring.booto
                              mybatis-spring-boot-starter
                              2.2.2
                          
                          
                          
                              cn.hutool
                              hutool-all
                              5.7.20
                          
                          
                              org.springframework.cloud
                              spring-cloud-starter-oauth2
                          
                          
                              org.springframework.cloud
                              spring-cloud-starter-security
                          
                      
                      
                          
                              
                                  org.springframework.cloud
                                  spring-cloud-dependencies
                                  ${spring-cloud.version}
                                  pom
                                  import
                              
                          
                      
                      
                          
                              
                                  org.springframework.boot
                                  spring-boot-maven-plugin
                              
                          
                      
                  
                  

                  application.yml

                  server:
                    port: 8084
                  spring:
                    # mysql连接信息
                    datasource:
                      # mysql8之后
                      driver-class-name: com.mysql.cj.jdbc.Driver
                      url: jdbc:mysql://43.143.132.109:3306/index?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
                      username: root
                      password: Weikai19991015.
                  security:
                    oauth2:
                      resource:
                        jwt:
                          key-uri: http://localhost:8888/oauth/token_key
                  

                  Config文件

                  package com.weige.javaskillpoint.config;
                  import org.springframework.boot.web.client.RestTemplateBuilder;
                  import org.springframework.context.annotation.Bean;
                  import org.springframework.context.annotation.Configuration;
                  import org.springframework.web.client.RestTemplate;
                  @Configuration
                  public class Config {
                      @Bean
                      public RestTemplate restTemplate(RestTemplateBuilder builder) {
                          return builder.build();
                      }
                  }
                  

                  JwtConfig文件

                  package com.weige.javaskillpoint.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.core.io.ClassPathResource;
                  import org.springframework.core.io.Resource;
                  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 org.springframework.util.FileCopyUtils;
                  import java.io.IOException;
                  @Configuration
                  public class JwtConfig {
                      public static final String public_cert = "public.key";
                      @Autowired
                      private JwtAccessTokenConverter jwtAccessTokenConverter;
                      @Bean
                      @Qualifier("tokenStore")
                      public TokenStore tokenStore() {
                          return new JwtTokenStore(jwtAccessTokenConverter);
                      }
                      @Bean
                      protected JwtAccessTokenConverter jwtAccessTokenConverter() {
                          JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
                          Resource resource = new ClassPathResource(public_cert);
                          String publicKey;
                          try {
                              publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
                          } catch (IOException e) {
                              throw new RuntimeException(e);
                          }
                          // 设置校验公钥
                          converter.setVerifierKey(publicKey);
                          // 设置证书签名密码,否则报错
                          converter.setSigningKey("kaikeba");
                          return converter;
                      }
                  }
                  

                  ResourceServerConfiguration文件

                  package com.weige.javaskillpoint.config;
                  import org.springframework.beans.factory.annotation.Autowired;
                  import org.springframework.context.annotation.Configuration;
                  import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
                  import org.springframework.security.config.annotation.web.builders.HttpSecurity;
                  import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
                  import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
                  import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
                  import org.springframework.security.oauth2.provider.token.TokenStore;
                  @Configuration
                  @EnableResourceServer
                  @EnableGlobalMethodSecurity(prePostEnabled = true)
                  public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
                      @Autowired
                      private TokenStore tokenStore;
                      @Override
                      public void configure(HttpSecurity http) throws Exception {
                          http.csrf().disable().authorizeRequests()
                                  .antMatchers("/user/**")
                                  .permitAll()
                                  .antMatchers("/book/**").hasRole("admin")
                                  .antMatchers("/**")
                                  .authenticated();
                      }
                      @Override
                      public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
                          resources.tokenStore(tokenStore);
                      }
                  }
                  

                  HelloController文件

                  package com.weige.javaskillpoint.controller;
                  import org.springframework.security.access.annotation.Secured;
                  import org.springframework.security.access.prepost.PreAuthorize;
                  import org.springframework.security.core.Authentication;
                  import org.springframework.security.core.context.SecurityContextHolder;
                  import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
                  import org.springframework.web.bind.annotation.GetMapping;
                  import org.springframework.web.bind.annotation.PutMapping;
                  import org.springframework.web.bind.annotation.RequestMapping;
                  import org.springframework.web.bind.annotation.RestController;
                  import java.util.Arrays;
                  @RestController
                  @RequestMapping("/cms")
                  public class HelloController {
                      @GetMapping("/getCurrentUser")
                      public Object getCurrentUser(Authentication authentication) {
                          return authentication;
                      }
                      @GetMapping("/index/user")
                      @PreAuthorize("hasRole('ROLE_USER')")
                      public String index() {
                          return "index/user";
                      }
                      @GetMapping("/index/admin")
                      @PreAuthorize("hasRole('ROLE_ADMIN')")
                      public String index2() {
                          return "index/admin";
                      }
                  }
                  

                  JavaSkillPointApplication文件

                  package com.weige.javaskillpoint;
                  import org.mybatis.spring.annotation.MapperScan;
                  import org.springframework.boot.SpringApplication;
                  import org.springframework.boot.autoconfigure.SpringBootApplication;
                  @SpringBootApplication
                  @MapperScan("com.weige.javaskillpoint.dao")
                  public class JavaSkillPointApplication {
                      public static void main(String[] args) {
                          SpringApplication.run(JavaSkillPointApplication.class, args);
                      }
                  }
                  

                  这里别忘记了生成的JWT公钥文件 放到reources目录下即可

                  两个项目都创建完成,在启动项目时。要注意先后顺序,先启动授权项目,在启动资源项目。因为资源项目会请求授权项目中的token中JTW对应的公钥解析是否对应私钥。

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第45张

                  3.3 授权接口调用并测试资源接口

                  密码模式:

                  申请令牌 PostMan请求 localhost:8888/oauth/token?grant_type=password&username=user&password=123456&scope=read

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第46张

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第47张

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第48张

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第49张

                  资源项目接口测试:

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第50张

                  资源服务器接口调用 USER http://localhost:8084/cms/index/user

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第51张

                  资源服务器接口调用 ADMIN http://localhost:8084/cms/index/admin

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第52张

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第53张

                  资源服务器接口调用 ADMIN http://localhost:8084/cms/index/admin

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第54张

                  3.4 资源项目中添加用户登录接口 获取令牌(token)返回给前端

                  资源项目添加几个类:

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第55张

                  AdminConstants文件

                  package com.weige.javaskillpoint.constant;
                  public interface AdminConstants {
                      /**
                       * 请求头key
                       */
                      String AUTHORIZATION_KEY = "Authorization";
                      /**
                       * Basic
                       */
                      String BASIC_KEY = "Basic ";
                      /**
                       * 用户名key
                       */
                      String USERNAME_KEY = "username";
                      /**
                       * 密码key
                       */
                      String PASSWORD_KEY = "password";
                      /**
                       * 认证类型key
                       */
                      String GRANT_TYPE_KEY = "grant_type";
                      /**
                       * 授权范围key
                       */
                      String SCOPE_KEY = "scope";
                      /**
                       * 分隔符
                       */
                      String SPLIT = ":";
                  }
                  

                  LoginController文件

                  package com.weige.javaskillpoint.controller;
                  import com.weige.javaskillpoint.entity.LoginRequestDTO;
                  import com.weige.javaskillpoint.service.LoginService;
                  import org.springframework.http.ResponseEntity;
                  import org.springframework.security.oauth2.common.OAuth2AccessToken;
                  import org.springframework.web.bind.annotation.PostMapping;
                  import org.springframework.web.bind.annotation.RequestBody;
                  import org.springframework.web.bind.annotation.RequestMapping;
                  import org.springframework.web.bind.annotation.RestController;
                  import javax.annotation.Resource;
                  @RestController
                  @RequestMapping("/user")
                  public class LoginController {
                      @Resource
                      private LoginService loginService;
                      /**
                       * 用户登录
                       *
                       * @param loginRequestDTO 登录请求DTO
                       * @return org.springframework.http.ResponseEntity
                       */
                      @PostMapping("/login")
                      public ResponseEntity login(@RequestBody LoginRequestDTO loginRequestDTO) {
                          return loginService.login(loginRequestDTO);
                      }
                  }
                  

                  LoginRequestDTO文件

                  package com.weige.javaskillpoint.entity;
                  import lombok.Getter;
                  import lombok.Setter;
                  import lombok.ToString;
                  @Setter
                  @Getter
                  @ToString
                  public class LoginRequestDTO {
                      /**
                       * 用户名
                       */
                      private String username;
                      /**
                       * 密码
                       */
                      private String password;
                  }
                  

                  LoginService文件

                  package com.weige.javaskillpoint.service;
                  import com.weige.javaskillpoint.entity.LoginRequestDTO;
                  import org.springframework.http.ResponseEntity;
                  import org.springframework.security.oauth2.common.OAuth2AccessToken;
                  public interface LoginService {
                      /**
                       * 用户登录
                       *
                       * @param loginRequestDTO 登录请求DTO
                       * @return org.springframework.http.ResponseEntity
                       */
                      ResponseEntity login(LoginRequestDTO loginRequestDTO);
                  }
                  

                  LoginServiceImpl文件

                  package com.weige.javaskillpoint.service.impl;
                  import com.weige.javaskillpoint.constant.AdminConstants;
                  import com.weige.javaskillpoint.entity.LoginRequestDTO;
                  import com.weige.javaskillpoint.service.LoginService;
                  import org.apache.commons.lang3.StringUtils;
                  import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties;
                  import org.springframework.http.HttpEntity;
                  import org.springframework.http.HttpHeaders;
                  import org.springframework.http.HttpMethod;
                  import org.springframework.http.ResponseEntity;
                  import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
                  import org.springframework.security.oauth2.common.OAuth2AccessToken;
                  import org.springframework.stereotype.Service;
                  import org.springframework.util.LinkedMultiValueMap;
                  import org.springframework.util.MultiValueMap;
                  import org.springframework.web.client.RestTemplate;
                  import javax.annotation.Resource;
                  import java.util.Base64;
                  import java.util.Collections;
                  @Service
                  public class LoginServiceImpl implements LoginService {
                      @Resource
                      private RestTemplate restTemplate;
                      @Resource
                      private OAuth2ClientProperties oAuth2ClientProperties;
                      @Resource
                      private OAuth2ProtectedResourceDetails oAuth2ProtectedResourceDetails;
                      /**
                       * 用户登录
                       *
                       * @param loginRequestDTO 登录请求DTO
                       * @return org.springframework.http.ResponseEntity
                       */
                      @Override
                      public ResponseEntity login(LoginRequestDTO loginRequestDTO) {
                          HttpHeaders headers = new HttpHeaders();
                          headers.set(AdminConstants.AUTHORIZATION_KEY, StringUtils.join(AdminConstants.BASIC_KEY, Base64.getEncoder().encodeToString(StringUtils.join(oAuth2ClientProperties.getClientId(), AdminConstants.SPLIT, oAuth2ClientProperties.getClientSecret()).getBytes())));
                          // 组装请求参数
                          MultiValueMap map = new LinkedMultiValueMap<>(4);
                          map.put(AdminConstants.USERNAME_KEY, Collections.singletonList(loginRequestDTO.getUsername()));
                          map.put(AdminConstants.PASSWORD_KEY, Collections.singletonList(loginRequestDTO.getPassword()));
                          map.put(AdminConstants.GRANT_TYPE_KEY, Collections.singletonList(oAuth2ProtectedResourceDetails.getGrantType()));
                          map.put(AdminConstants.SCOPE_KEY, oAuth2ProtectedResourceDetails.getScope());
                          // 请求到授权服务器,将授权完的用户信息存到授权服务器,并申请令牌
                          return restTemplate.exchange(oAuth2ProtectedResourceDetails.getAccessTokenUri(), HttpMethod.POST, new HttpEntity(map, headers), OAuth2AccessToken.class);
                      }
                  }
                  

                  application.yml文件

                  server:
                    port: 8084
                  spring:
                    # mysql连接信息
                    datasource:
                      # mysql8之后
                      driver-class-name: com.mysql.cj.jdbc.Driver
                      url: jdbc:mysql://43.143.132.109:3306/index?useUnicode=true&characterEncoding=utf8&tinyInt1isBit=false&useSSL=false&serverTimezone=GMT
                      username: root
                      password: Weikai19991015.
                  security:
                    oauth2:
                      resource:
                        jwt:
                          key-uri: http://localhost:8888/oauth/token_key
                      client:
                        access-token-uri: http://localhost:8888/oauth/token #令牌端点
                        user-authorization-uri: http://localhost:8888/oauth/authorize #授权端点
                        client-id: cms
                        client-secret: 123456
                        grant-type: password
                        scope: read,write
                  

                  调用资源服务登录接口:PostMan调用 http://localhost:8084/user/login

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第56张

                  拿到获取的token访问资源服务的接口 http://localhost:8084/cms/index/user

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第57张

                  用admin登录

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第58张

                  拿到获取的token访问资源服务的接口 http://localhost:8084/cms/index/admin

                  Spring Security实现OAuth2协议及实战,在这里插入图片描述,第59张

                  完结撒花 !