主项目链接:https://gitee.com/java_wxid/java_wxid
项目架构及博文总结:

  • 点击:【使用Spring Boot快速构建应用】
  • 点击:【使用Spring Cloud Open Feign基于动态代理动态构造请求实现与其他系统进行交互】
  • 点击:【使用Spring Cloud Hystrix实现服务容错、熔断、降级、监控】
  • 点击:【使用Spring Cloud Ribbon以库的方式集成到服务的消费方实现客户端负载均衡】
  • 点击:【使用Spring Cloud Gateway作为API网关服务进行请求拦截、服务分发、降级、限流】
  • 点击:【使用Spring Cloud Security Oauth2作为微服务统一认证中心实现用户认证和授权访问】
  • 点击:【使用Spring Cloud Stream作为消息驱动用于动态的切换中间件】
  • 点击:【使用Spring Cloud Skywalking基于字节码注入通过探针方式进行链路追踪、分布式追踪、性能指标分析、应用和服务依赖分析】
  • 点击:【使用Spring Cloud Alibaba Nacos实现服务注册/发现/续约/剔除/下线、心跳检测、服务配置管理、基于长轮训机制实现配置动态变更】
  • 点击:【使用Spring Cloud Alibaba Seata作为对项目代码无入侵的分布式事务解决方案】
  • 点击:【使用Spring Cloud Alibaba Sentinel实现高可用流量防护】
  • 点击:【使用Apache ShardingSphere作为关系型数据库中间件实现分库分表、读写分离】
  • 点击:【使用Apache Mybatis作为持久层框架用于定制化SQL、存储过程以及高级映射】
  • 点击:【使用Redis作为高性能分布式缓存数据库】
  • 点击:【使用ElasticSearch全文搜索】
  • 点击:【使用MongoDB非关系型数据库】
  • 点击:【使用xxl-job作为分布式任务调度平台】
  • 点击:【使用Elasticsearch + Logstash + Kibana作为日志收集系统】
  • 点击:【使用Apifox作为API文档、API调试、API Mock、API自动化测试】
  • 点击:【使用Apache Spark作为基于内存计算的大数据分析引擎用于批处理、交互式查询】
  • 点击:【使用ETL工具将数据源抽取到HDFS作为高可靠、高吞吐量的分布式文件系统存储,通过Hive清洗、处理和计算原始数据,Hive清洗处理后的结果,将存入Hbase,海量数据随机查询场景从HBase查询数据】
  • 点击:【使用领域驱动DDD设计和设计模式进行开发】
  • 点击:【使用Netty基于Java NIO封装的高性能的网络通信框架】
  • 点击:【使用k8s、docker、docker-compose、宝塔面板进行环境搭建和部署】
  • 点击:【使用Vue渐进式JavaScript框架作为适用场景丰富的Web前端框架】
  • 点击:【分享人才筛选、工作分配、高效办公、项目推动等团队管理经验】

项目模块:
前期规划,实现部分

java_wxid
├── demo                                                            // 演示模块
│     └── 模块名称:apache-mybatis-demo模块                            //Apache Mybatis集成(已实现并有博文总结)
│     └── 模块名称:apache-shardingsphere-demo模块                     //Apache ShardingSphere集成(已实现并有博文总结)
│     └── 模块名称:design-demo模块                                    //设计模式实战落地(已实现并有博文总结)
│     └── 模块名称:elasticsearch-demo模块                             //ElasticSearch集成(已实现并有博文总结)
│     └── 模块名称:mongodb-demo模块                                   //MongoDB集成(已实现并有博文总结)
│     └── 模块名称:redis-demo模块                                     //Redis集成(已实现并有博文总结)
│     └── 模块名称:spring-boot-demo模块                               //Spring Boot快速构建应用(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-nacos-demo模块                //Spring Cloud Alibaba Nacos集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-seata-demo模块                //Spring Cloud Alibaba Seata集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-alibaba-sentinel-demo模块             //Spring Cloud Alibaba Sentinel集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-gateway-demo模块                      //Spring Cloud Gateway集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-hystrix-demo模块                      //Spring Cloud Hystrix集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-open-feign-demo模块                   //Spring Cloud Open Feign集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-ribbon-demo模块                       //Spring Cloud Ribbon集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-security-oauth2-demo模块              //Spring Cloud Security Oauth2集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-security-oauth2-sso-client-demo模块   //Spring Cloud Security Oauth2集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-skywalking-demo模块                   //Spring Cloud Skywalking集成(已实现并有博文总结)
│     └── 模块名称:spring-cloud-stream-demo模块                       //Spring Cloud Stream集成(已实现并有博文总结)
│     └── 模块名称:swagger-demo模块                                   //springfox-swagger2集成(已实现并有博文总结)
│     └── 模块名称:xxl-job模块                                        //xxl-job集成(已实现并有博文总结)
│     └── 模块名称:apache-spark-demo模块                              //Apache Spark集成
│     └── 模块名称:etl-hdfs-hive-hbase-demo模块                       //ETL、HDFS、Hive、Hbase集成
│     └── 模块名称:ddd-mode-demo模块                                  //DDD领域设计
│     └── 模块名称:netty-demo模块                                     //Netty集成
│     └── 模块名称:vue-demo模块                                       //前端vue集成
├── document                                                        // 文档
│     └── JavaKnowledgeDocument                                     //java知识点
│           └── java基础知识点.md
│           └── mq知识点.md
│           └── mysql知识点.md
│           └── redis知识点.md
│           └── springcould知识点.md
│           └── spring知识点.md
│     └── FounderDocument                                           //创始人
│           └── 创始人.md

系列文章:快速集成各种微服务相关的技术,帮助大家可以快速集成到自己的项目中,节约开发时间。
提示:系列文章还未全部完成,后续的文章,会慢慢补充进去的。

文章目录

  • 创建spring-cloud-security-oauth2-demo项目
    • 修改pom.xml
    • 创建bootstrap.yml文件
    • 修改application.properties文件
    • 创建一个空的config.properties文件
    • 创建jwt.jks文件
    • 修改SpringCloudSecurityOauth2DemoApplication
    • 创建数据库表结构
    • 创建AuthResourceServerConfig
    • 创建AuthServerJdbcTokenStoreConfig.java
    • 创建AuthServerJwtTokenStoreConfig
    • 创建AuthServerRedisTokenStoreConfig.java
    • 创建AuthTokenEnhancer
    • 创建JwtTokenStoreConfig
    • 创建RedisStoreConfig
    • 创建WebSecurityConfig
    • 创建SecurityOauth2Controller
    • 创建AppUserinfoEntity
    • 创建ResultData
    • 创建UserInfoFeignService
    • 创建JWTAuthenticationEntryPoint.java
    • 创建JWTAuthenticationFilter.java
    • 创建JWTAuthorizationFilter.java
    • 创建UserServiceHystrix
    • 创建JwtCAProperties
    • 创建AppUserDetailsService
    • 创建UserInfoDetails
    • 创建JwtTokenUtil
  • 验证Spring Cloud Security Oauth2是否工作
    • 授权码模式
      • 获取授权码
      • 授权登录之后会进行回调获取授权码
      • 填入授权码code获取获取access_token
    • password模式
    • 刷新令牌获取access_token
    • 发起请求使用access_token进行授权获取登录用户信息
  • 创建spring-cloud-security-oauth2-sso-client-demo项目(实现单点登录)
    • 修改pom.xml文件
    • 创建bootstrap.yml文件
    • 修改application.properties文件
    • 修改SpringCloudSecurityOauth2SsoClientDemoApplication
    • 创建UserController
    • 校验请求是否有到授权服务器进行授权
      • 授权登录之会进行回调,返回授权码
      • 拿到授权码获取access_token

创建spring-cloud-security-oauth2-demo项目

项目代码:https://gitee.com/java_wxid/java_wxid/tree/master/demo/spring-cloud-security-oauth2-demo
项目结构如下(示例):

修改pom.xml

代码如下(示例):

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion><groupId>com.example</groupId><artifactId>spring-cloud-security-oauth2-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-cloud-security-oauth2-demo</name><description>Demo project for Spring Boot</description><!--    属性配置--><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><!--引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系--><spring.boot.version>2.3.12.RELEASE</spring.boot.version><spring.cloud.version>Hoxton.SR12</spring.cloud.version><spring.cloud.alibaba.version>2.2.7.RELEASE</spring.cloud.alibaba.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--代表web模块,在这个模块中含了许多JAR包,有spring相关的jar,内置tomcat服务器,jackson等,这些web项目中常用的的功能都会自动引入--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Alibaba Nacos 配置 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--        在SpringBoot 2.4.x的版本之后,对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持,其实这个jar包里什么都没有,就只有一个标识类Marker,用来标识要开启Bootstrap配置文件的支持,由于父类用了2.5.6版本需要导入如下的依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId><version>3.1.0</version></dependency><!-- spring security oauth2--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><!-- JWT依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
<!--        lombok插件--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>RELEASE</version><scope>compile</scope></dependency>
<!--        commons-lang3工具包--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.10</version></dependency><!--openfeign客户端依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-openfeign-core</artifactId><version>2.2.6.RELEASE</version></dependency><!--引入HttpClient依赖--><dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId></dependency><!-- 引入Feign Slf4j --><dependency><groupId>com.netflix.feign</groupId><artifactId>feign-slf4j</artifactId><version>8.14.4</version></dependency><!--        jdbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
<!--        fastjson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.62</version></dependency></dependencies><!--引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系--><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>${spring.boot.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring.cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring.cloud.alibaba.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.4</version><configuration><source>${java.version}</source><target>${java.version}</target><encoding>${project.build.sourceEncoding}</encoding></configuration></plugin></plugins><resources><resource><directory>src/main/resources</directory><filtering>true</filtering><excludes><exclude>**/*.jks</exclude></excludes></resource><resource><directory>src/main/resources</directory><filtering>false</filtering><includes><include>**/*.jks</include></includes></resource></resources></build>
</project>

创建bootstrap.yml文件

代码如下(示例):

#bootstrap.yml优先级比application.yml优先级高
spring:#prefix−{spring.profile.active}.${file-extension}#nacos会根据当前环境去拼接配置名称查找相应配置文件,#示例:{spring.application.name}-{spring.profiles.active}-{spring.cloud.nacos.config.file-extension}#获取到值:nacos-autoconfig-service-dev.ymlprofiles:#开发环境dev,测试环境test,生产环境prodactive: devapplication:#配置应用的名称,用于获取配置name: security-oauth2main:allow-bean-definition-overriding: truecloud:nacos:discovery:# 服务注册地址server-addr: ip:8848config:#nacos配置中心地址server-addr: ip:8848#配置中心的命名空间idnamespace: 9e50b6d9-6c3d-4e7a-b701-10f085e4b98d#配置分组,默认没有也可以group: DEFAULT_GROUP#配置文件后缀,用于拼接配置配置文件名称,目前只支持yaml和propertiesfile-extension: yaml#配置自动刷新refresh-enabled: true#配置文件的前缀,默认是application.name的值,如果配了prefix,就取prefix的值#prefix: nacos-autoconfig-service-${spring.profile.active}# 配置编码encode: UTF-8username: nacospassword: nacosdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://ip:3306/oauth2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2b8username: rootpassword: ca0a997ee4770063hikari:minimum-idle: 5idle-timeout: 600000maximum-pool-size: 10auto-commit: truepool-name: MyHikariCPmax-lifetime: 3000000  #连接最大存活时间,默认值30分钟.设置应该比mysql设置的超时时间短connection-timeout: 30000connection-test-query: SELECT 1 #连接测试查询redis:host: ipdatabase: 0client-name: rootpassword: ca0a997ee4770063
auth:jwt:keyPairName: jwt.jkskeyPairAlias: jwtkeyPairSecret: 123456keyPairStoreSecret: 123456

修改application.properties文件

server.port=8807

创建一个空的config.properties文件

创建jwt.jks文件

# Keytool 是一个java提供的证书管理工具
#    -alias:密钥的别名
#    -keyalg:使用的hash算法
#    -keypass:密钥的访问密码
#    -keystore:密钥库文件名,jwt.jks -> 生成的证书
#    -storepass:密钥库的访问密码
keytool -genkeypair -alias jwt -keyalg RSA -keypass 123456 -keystore jwt.jks -storepass 123456# 查询证书
keytool -list -keystore jwt.jks

把生成的文件复制到项目的resource目录下面

修改SpringCloudSecurityOauth2DemoApplication

代码如下(示例):

package com.example.springcloudsecurityoauth2demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@EnableDiscoveryClient
@SpringBootApplication
public class SpringCloudSecurityOauth2DemoApplication {public static void main(String[] args) {SpringApplication.run(SpringCloudSecurityOauth2DemoApplication.class, args);}}

创建数据库表结构

代码如下(示例):

#官方的sql: https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sqlCREATE TABLE `clientdetails` (`appId` varchar(128) NOT NULL,`resourceIds` varchar(255) DEFAULT NULL,`appSecret` varchar(255) DEFAULT NULL,`scope` varchar(255) DEFAULT NULL,`grantTypes` varchar(255) DEFAULT NULL,`redirectUrl` varchar(255) DEFAULT NULL,`authorities` varchar(255) DEFAULT NULL,`access_token_validity` int(11) DEFAULT NULL,`refresh_token_validity` int(11) DEFAULT NULL,`additionalInformation` varchar(4096) DEFAULT NULL,`autoApproveScopes` varchar(255) DEFAULT NULL,PRIMARY KEY (`appId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `oauth_access_token` (`token_id` varchar(255) DEFAULT NULL,`token` blob,`authentication_id` varchar(128) NOT NULL,`user_name` varchar(255) DEFAULT NULL,`client_id` varchar(255) DEFAULT NULL,`authentication` blob,`refresh_token` varchar(255) DEFAULT NULL,PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `oauth_approvals` (`userId` varchar(255) DEFAULT NULL,`clientId` varchar(255) DEFAULT NULL,`scope` varchar(255) DEFAULT NULL,`status` varchar(10) DEFAULT NULL,`expiresAt` timestamp NULL DEFAULT NULL,`lastModifiedAt` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `oauth_client_details` (`client_id` varchar(128) NOT NULL,`resource_ids` varchar(255) DEFAULT NULL,`client_secret` varchar(255) DEFAULT NULL,`scope` varchar(255) DEFAULT NULL,`authorized_grant_types` varchar(255) DEFAULT NULL,`web_server_redirect_uri` varchar(255) DEFAULT NULL,`authorities` varchar(255) DEFAULT NULL,`access_token_validity` int(11) DEFAULT NULL,`refresh_token_validity` int(11) DEFAULT NULL,`additional_information` varchar(4096) DEFAULT NULL,`autoapprove` varchar(255) DEFAULT NULL,PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `oauth_client_token` (`token_id` varchar(255) DEFAULT NULL,`token` blob,`authentication_id` varchar(128) NOT NULL,`user_name` varchar(255) DEFAULT NULL,`client_id` varchar(255) DEFAULT NULL,PRIMARY KEY (`authentication_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `oauth_code` (`code` varchar(255) DEFAULT NULL,`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;CREATE TABLE `oauth_refresh_token` (`token_id` varchar(255) DEFAULT NULL,`token` blob,`authentication` blob
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入语句

insert into `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('client','auth','$2a$10$dis6W.9y3lqGKHCM89WCa.XiE4zkGND63TdKzLtR/jnSJvTsoOcy.','All','authorization_code,password,refresh_token,implicit','http://localhost:8807/securityOauth2/getCodeByCallback',NULL,NULL,NULL,NULL,'true');

如下图(示例):

创建AuthResourceServerConfig

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.config;import org.springframework.context.annotation.Configuration;
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;/*** @Author: liaozhiwei* @Description: 资源服务配置* @Date: Created in 18:19 2022/8/23*/
@Configuration
@EnableResourceServer
public class AuthResourceServerConfig  extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {//利用RequestMatcher对象来进行路径匹配了,调用了antMatchers方法来定义什么样的请求可以放过,什么样的请求需要验证http.authorizeRequests().anyRequest().authenticated().and().requestMatchers().antMatchers("/user/**");}
}

创建AuthServerJdbcTokenStoreConfig.java

这个是基于DB模式配置授权服务器存储第三方客户端的信息,由于DB/Jwt/Redis三种方式选择其中一个进行存储,目前测试过可行,所以注释了

代码如下(示例):

//package com.example.springcloudsecurityoauth2demo.config;
//
//import com.example.springcloudsecurityoauth2demo.service.AppUserDetailsService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Bean;
//import org.springframework.context.annotation.Configuration;
//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.ClientDetailsService;
//import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
//import org.springframework.security.oauth2.provider.token.TokenEnhancer;
//import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
//import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
//import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
//import javax.sql.DataSource;
//import java.util.ArrayList;
//import java.util.List;
//
///**
// * @Author: liaozhiwei
// * @Description: 第一种方式:基于DB模式配置授权服务器存储第三方客户端的信息
// * @Date: Created in 18:17 2022/8/23
// */
//@Configuration
//@EnableAuthorizationServer
//public class AuthServerJdbcTokenStoreConfig extends AuthorizationServerConfigurerAdapter {//
//      //第一种方式:使用密码模式需要配置(使用jdbc的方式)
//    @Autowired
//    private DataSource dataSource;
//    @Bean
//    public JdbcTokenStore jdbcTokenStore(){//        return new JdbcTokenStore(dataSource);
//    }
//    @Bean
//    public ClientDetailsService clientDetailsService(){//        return new JdbcClientDetailsService(dataSource);
//    }
//
//    @Autowired
//    private JwtAccessTokenConverter jwtAccessTokenConverter;
//
//    @Autowired
//    private AppUserDetailsService userDetailService;
//
//    @Autowired
//    private AuthenticationManager authenticationManagerBean;
//
//    @Autowired
//    private AuthTokenEnhancer authTokenEnhancer;
//
//    /**
//     * @Description 第三方信息的存储
//     **/
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//        /**
//         * 第一步
//         *授权码模式(安全级别最高)
//         *http://localhost:8807/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all
//         *或者
//         *http://localhost:8807/oauth/authorize?response_type=code&client_id=client
//         *password模式
//         *http://localhost:8807/oauth/token?username=liaozhiwei&password=123456&grant_type=password&client_id=client&client_secret=client_secret&scope=all
//         *刷新令牌
//         *http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=client_secret&refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJsaWFvemhpd2VpIiwic2NvcGUiOlsiYWxsIl0sImF0aSI6IjJiYjg5NDY5LWIyNmYtNGQwNC05YTZjLTJjYmZkYjIzMDgyNyIsImV4cCI6MTY2MjE3ODkzMiwiYXV0aG9yaXRpZXMiOlsiYWRtaW4iXSwianRpIjoiNzBmOTc0NWItNGZmOS00ZTY5LThiOWMtNzY5ZGNkODc5NTcwIiwiY2xpZW50X2lkIjoiY2xpZW50In0.Uy6s5uIT2h_vv6DezssqzA1d7iNpqyfNReiAygmYrapPuc1Beyetoxbf3_zduD8BhZkKva7Qna_L9lFQKZuzzSx25RLgG07YzDZnuUPkCVYisxZ4bhmOuJYndKzrZmZBqmK2P9MQwLhasEgcpZoR5RJurV15fZOO5IvOI6xvgM0XkqalnEwYWf5e5JYLEEBqQqTpkEoP6wH3SSBsRFuH10l6qKqUXFd_nO37hO1p-d2uX-qMBTGPZ57xiaz97x5FLGxh2dbskmxyTnf-jAiTHlRdrfvIHDh312uW4iyENZpg8HEg3OjUHYc-7OY4U9UrHQx0YQbJ01SuKLCFEIx-aA
//         */
//        /**
//         * 第二步
//         * 获取access_token
//         * http://localhost:8807/oauth/token?grant_type=authorization_code&client_id=client&client_secret=client_secret&code=07Sn4f
//         */
//        // 第三方信息的存储   基于jdbc
//        clients.withClientDetails(clientDetailsService());
//    }
//
//    @Override
//    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {//        //配置JWT的内容增强器
//        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
//        List<TokenEnhancer> delegates = new ArrayList<>();
//        delegates.add(authTokenEnhancer);
//        delegates.add(jwtAccessTokenConverter);
//        enhancerChain.setTokenEnhancers(delegates);
//
//        //第一种:使用密码模式需要配置(使用jdbc的方式)
//        endpoints.authenticationManager(authenticationManagerBean)
//                .reuseRefreshTokens(false)  //refresh_token是否重复使用
//                .userDetailsService(userDetailService) //刷新令牌授权包含对用户信息的检查
//                .tokenStore(new JdbcTokenStore(dataSource))  //指定token存储策略是jwt,存储到mysql
//                .accessTokenConverter(jwtAccessTokenConverter)
//                .tokenEnhancer(enhancerChain) //配置tokenEnhancer
//                .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST,HttpMethod.DELETE,HttpMethod.PUT); //支持GET,POST请求,DELETE请求,PUT请求
//    }
//
//    /**
//     * 授权服务器安全配置
//     * @param security
//     * @throws Exception
//     */
//    @Override
//    public void configure(AuthorizationServerSecurityConfigurer security) {//        //第三方客户端校验token需要带入 clientId 和clientSecret来校验
//        security.checkTokenAccess("isAuthenticated()")
//                .tokenKeyAccess("isAuthenticated()");//来获取我们的tokenKey需要带入clientId,clientSecret
//        //允许表单认证
//        security.allowFormAuthenticationForClients();
//    }
//}
//

创建AuthServerJwtTokenStoreConfig

这个是基于jwt.jks文件授权服务器存储第三方客户端的信息,由于DB/Jwt/Redis三种方式选择其中一个进行存储,目前测试过可行

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.config;import com.example.springcloudsecurityoauth2demo.service.AppUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
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.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 java.util.ArrayList;
import java.util.List;/*** @Author: liaozhiwei* @Description: 第二种方式:基于jwt.jks文件授权服务器存储第三方客户端的信息* @Date: Created in 18:17 2022/8/23*/
@Configuration
@EnableAuthorizationServer
public class AuthServerJwtTokenStoreConfig extends AuthorizationServerConfigurerAdapter {//第二种方式:使用密码模式需要配置(使用jwt文件的方式)@Autowired@Qualifier("jwtTokenStore")private TokenStore jwtTokenStore;@Autowiredprivate JwtAccessTokenConverter jwtAccessTokenConverter;@Autowiredprivate AppUserDetailsService userDetailService;@Autowiredprivate AuthenticationManager authenticationManagerBean;@Autowiredprivate AuthTokenEnhancer authTokenEnhancer;@Autowiredprivate PasswordEncoder passwordEncoder;/*** @Description 第三方信息的存储**/@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {/*** 第一种方式:授权码模式(安全级别最高)获取access_token* 第一步* http://127.0.0.1:8807/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all*或者* http://127.0.0.1:8807/oauth/authorize?response_type=code&client_id=client* 第二步* 获取access_token* http://127.0.0.1:8807/oauth/token?grant_type=authorization_code&client_id=client&client_secret=client_secret&code=JQFXW7* 第二种方式:password模式获取access_token* http://127.0.0.1:8807/oauth/token?username=liaozhiwei&password=123456&grant_type=password&client_id=client&client_secret=client_secret&scope=all* 刷新令牌获取access_token*http://127.0.0.1:8807/oauth/token?grant_type=refresh_token&client_id=client&client_secret=client_secret&refresh_token=         *//*** 其他服务发起请求使用access_token进行授权* http://127.0.0.1:8808/securityOauth2/getUserByTokenStore?access_token=* http://127.0.0.1:8808/securityOauth2/getUserByAuthentication?access_token=* http://127.0.0.1:8808/securityOauth2/getUserByRequest?access_token=* */clients.inMemory()//配置client_id.withClient("client")//配置client-secret.secret(passwordEncoder.encode("client_secret"))//配置访问token的有效期.accessTokenValiditySeconds(3600)//配置刷新token的有效期.refreshTokenValiditySeconds(864000)//配置redirect_uri,用于授权成功后跳转,可以配置多个,例如:.redirectUris("http://localhost:8081/login","http://localhost:8082/login").redirectUris("http://127.0.0.1:8807/securityOauth2/redirectUris")//自动授权配置.autoApprove(true)//配置申请的权限范围.scopes("all")/*** 配置grant_type,表示授权类型* authorization_code: 授权码* password: 密码* client_credentials: 客户端* refresh_token: 更新令牌*/.authorizedGrantTypes("authorization_code","password","refresh_token");}@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {//配置JWT的内容增强器TokenEnhancerChain enhancerChain = new TokenEnhancerChain();List<TokenEnhancer> delegates = new ArrayList<>();delegates.add(authTokenEnhancer);delegates.add(jwtAccessTokenConverter);enhancerChain.setTokenEnhancers(delegates);//第二种:使用密码模式需要配置(使用jwt文件的方式)endpoints.authenticationManager(authenticationManagerBean) //使用密码模式需要配置.reuseRefreshTokens(false)  //refresh_token是否重复使用.userDetailsService(userDetailService) //刷新令牌授权包含对用户信息的检查.tokenStore(jwtTokenStore)  //配置存储令牌策略(使用jwt文件存储的方式).accessTokenConverter(jwtAccessTokenConverter).tokenEnhancer(enhancerChain) //配置tokenEnhancer.allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST,HttpMethod.DELETE,HttpMethod.PUT); //支持GET,POST请求,DELETE请求,PUT请求}/*** 授权服务器安全配置* @param security* @throws Exception*/@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {// 允许客户表单认证,不加的话/oauth/token无法访问security.allowFormAuthenticationForClients()// 对于CheckEndpoint控制器[框架自带的校验]的/oauth/token端点允许所有客户端发送器请求而不会被Spring-security拦截// 开启/oauth/token_key验证端口无权限访问.tokenKeyAccess("permitAll()")// 要访问/oauth/check_token必须设置为permitAll(),但这样所有人都可以访问了,设为isAuthenticated()又导致访问不了,这个问题暂时没找到解决方案// 开启/oauth/check_token验证端口认证权限访问.checkTokenAccess("permitAll()")
//                //第三方客户端校验token需要带入 clientId 和clientSecret来校验.checkTokenAccess("isAuthenticated()").tokenKeyAccess("isAuthenticated()");//来获取我们的tokenKey需要带入clientId,clientSecret//允许客户表单认证,不加的话/oauth/token无法访问security.allowFormAuthenticationForClients();}}

创建AuthServerRedisTokenStoreConfig.java

这个是基于Redis模式配置授权服务器存储第三方客户端的信息,由于DB/Jwt/Redis三种方式选择其中一个进行存储,目前测试过可行,所以注释掉了。
代码如下(示例):

//package com.example.springcloudsecurityoauth2demo.config;
//
//import org.springframework.beans.factory.annotation.Qualifier;
//import org.springframework.security.crypto.password.PasswordEncoder;
//import org.springframework.security.oauth2.provider.token.TokenStore;
//import com.example.springcloudsecurityoauth2demo.service.AppUserDetailsService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.context.annotation.Configuration;
//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.TokenEnhancer;
//import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
//import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
//import java.util.ArrayList;
//import java.util.List;
//
///**
// * @Author: liaozhiwei
// * @Description: 第三种方式:基于Redis模式配置授权服务器存储第三方客户端的信息
// * @Date: Created in 18:17 2022/8/23
// */
//@Configuration
//@EnableAuthorizationServer
//public class AuthServerRedisTokenStoreConfig extends AuthorizationServerConfigurerAdapter {//
//    //使用密码模式需要配置(使用redis的方式)
//    @Autowired
//    @Qualifier("redisTokenStore")
//    private TokenStore redisTokenStore;
//
//    @Autowired
//    private JwtAccessTokenConverter jwtAccessTokenConverter;
//
//    @Autowired
//    private AppUserDetailsService userDetailService;
//
//    @Autowired
//    private AuthenticationManager authenticationManagerBean;
//
//    @Autowired
//    private AuthTokenEnhancer authTokenEnhancer;
//
//    @Autowired
//    private PasswordEncoder passwordEncoder;
//
//    /**
//     * @Description 第三方信息的存储
//     **/
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//        /**
//         *授权码模式
//         *http://localhost:8807/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://www.baidu.com&scope=all
//         *或者
//         *http://localhost:8807/oauth/authorize?response_type=code&client_id=client
//         *password模式
//         *http://localhost:8807/oauth/token?username=liaozhiwei&password=123456&grant_type=password&client_id=client&client_secret=client-secret&scope=all
//         *刷新令牌
//         *http://localhost:8080/oauth/token?grant_type=refresh_token&client_id=client&client_secret=client-secret&refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJsaWFvemhpd2VpIiwic2NvcGUiOlsiYWxsIl0sImF0aSI6IjJiYjg5NDY5LWIyNmYtNGQwNC05YTZjLTJjYmZkYjIzMDgyNyIsImV4cCI6MTY2MjE3ODkzMiwiYXV0aG9yaXRpZXMiOlsiYWRtaW4iXSwianRpIjoiNzBmOTc0NWItNGZmOS00ZTY5LThiOWMtNzY5ZGNkODc5NTcwIiwiY2xpZW50X2lkIjoiY2xpZW50In0.Uy6s5uIT2h_vv6DezssqzA1d7iNpqyfNReiAygmYrapPuc1Beyetoxbf3_zduD8BhZkKva7Qna_L9lFQKZuzzSx25RLgG07YzDZnuUPkCVYisxZ4bhmOuJYndKzrZmZBqmK2P9MQwLhasEgcpZoR5RJurV15fZOO5IvOI6xvgM0XkqalnEwYWf5e5JYLEEBqQqTpkEoP6wH3SSBsRFuH10l6qKqUXFd_nO37hO1p-d2uX-qMBTGPZ57xiaz97x5FLGxh2dbskmxyTnf-jAiTHlRdrfvIHDh312uW4iyENZpg8HEg3OjUHYc-7OY4U9UrHQx0YQbJ01SuKLCFEIx-aA
//         */
//
//        clients.inMemory()
//                //配置client_id
//                .withClient("client")
//                //配置client-secret
//                .secret(passwordEncoder.encode("client-secret"))
//                //配置访问token的有效期
//                .accessTokenValiditySeconds(3600)
//                //配置刷新token的有效期
//                .refreshTokenValiditySeconds(864000)
//                //配置redirect_uri,用于授权成功后跳转,可以配置多个,例如:.redirectUris("http://localhost:8081/login","http://localhost:8082/login")
//                .redirectUris("http://www.baidu.com")
//                //配置申请的权限范围
//                .scopes("all")
//                //自动授权配置
//                .autoApprove(true)
//                /**
//                 * 配置grant_type,表示授权类型
//                 * authorization_code: 授权码
//                 * password: 密码
//                 * client_credentials: 客户端
//                 * refresh_token: 更新令牌
//                 * implicit:简化模式
//                 */
//                .authorizedGrantTypes("authorization_code","password","refresh_token");
//    }
//
//    @Override
//    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {//        //配置JWT的内容增强器
//        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
//        List<TokenEnhancer> delegates = new ArrayList<>();
//        delegates.add(authTokenEnhancer);
//        delegates.add(jwtAccessTokenConverter);
//        enhancerChain.setTokenEnhancers(delegates);
//
//        //使用密码模式需要配置(使用redis的方式)
//        endpoints.authenticationManager(authenticationManagerBean) //使用密码模式需要配置
//                .reuseRefreshTokens(false)  //refresh_token是否重复使用
//                .userDetailsService(userDetailService) //刷新令牌授权包含对用户信息的检查
//                .tokenStore(redisTokenStore)  //指定token存储到redis
//                .accessTokenConverter(jwtAccessTokenConverter)
//                .allowedTokenEndpointRequestMethods(HttpMethod.GET,HttpMethod.POST,HttpMethod.DELETE,HttpMethod.PUT); //支持GET,POST请求,DELETE请求,PUT请求
//    }
//
//    /**
//     * 授权服务器安全配置
//     * @param security
//     * @throws Exception
//     */
//    @Override
//    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {//        //第三方客户端校验token需要带入 clientId 和clientSecret来校验
//        security.checkTokenAccess("isAuthenticated()")
//                .tokenKeyAccess("isAuthenticated()");//来获取我们的tokenKey需要带入clientId,clientSecret
//        //允许表单认证
//        security.allowFormAuthenticationForClients();
//    }
//
//
//}
//

创建AuthTokenEnhancer

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.config;import org.springframework.security.core.userdetails.UserDetails;
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;/*** @Author: liaozhiwei* @Description: TODO* @Date: Created in 18:20 2022/8/23*/
public class AuthTokenEnhancer  implements TokenEnhancer {@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {UserDetails userinfoDetails = (UserDetails) authentication.getPrincipal();final Map<String, Object> additionalInfo = new HashMap<>();final Map<String, Object> retMap = new HashMap<>();//todo 这里暴露userId到Jwt的令牌中,后期可以根据自己的业务需要 进行添加字段additionalInfo.put("userName",userinfoDetails.getUsername());retMap.put("additionalInfo",additionalInfo);((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(retMap);return accessToken;}
}

创建JwtTokenStoreConfig

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.config;import com.example.springcloudsecurityoauth2demo.properties.JwtCAProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
import java.security.KeyPair;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;/*** @Author: liaozhiwei* @Description: jwt.jks文件形式存储* @Date: Created in 19:09 2022/8/23*/@Configuration
@EnableConfigurationProperties(value = JwtCAProperties.class)
public class JwtTokenStoreConfig {//第二种方式:使用jwt文件的方式@Beanpublic TokenStore jwtTokenStore(){return new JwtTokenStore(jwtAccessTokenConverter());}@Beanpublic AuthTokenEnhancer authTokenEnhancer() {return new AuthTokenEnhancer();}@Autowiredprivate JwtCAProperties jwtCAProperties;@Beanpublic KeyPair keyPair() {KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(jwtCAProperties.getKeyPairName()),jwtCAProperties.getKeyPairSecret().toCharArray());return keyStoreKeyFactory.getKeyPair(jwtCAProperties.getKeyPairAlias(),jwtCAProperties.getKeyPairStoreSecret().toCharArray());}@Beanpublic JwtAccessTokenConverter jwtAccessTokenConverter(){JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();//配置JWT使用的秘钥 非对称加密accessTokenConverter.setKeyPair(keyPair());return accessTokenConverter;}}

创建RedisStoreConfig

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;/*** @Author: liaozhiwei* @Description: 第三种方式:redis存储* @Date: Created in 19:09 2022/8/23*/
@Configuration
public class RedisStoreConfig {@Autowiredprivate RedisConnectionFactory redisConnectionFactory;//第三种:使用密码模式需要配置(使用redis的方式)
//    @Bean
//    public TokenStore redisTokenStore(){//        // access_token
//        return new RedisTokenStore(redisConnectionFactory);
//    }
}

创建WebSecurityConfig

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.config;//import com.example.springcloudsecurityoauth2demo.filter.JWTAuthenticationEntryPoint;
//import com.example.springcloudsecurityoauth2demo.filter.JWTAuthenticationFilter;
//import com.example.springcloudsecurityoauth2demo.filter.JWTAuthorizationFilter;
import com.example.springcloudsecurityoauth2demo.service.AppUserDetailsService;
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.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;/*** @Author: liaozhiwei* @Description: 配置SpringSecurity,“将Spring Security与Spring Gateway一起使用时出现无法访问javax.servlet.Filter”错误”,*  * 把Spring Gateway和Spring Security放在一起,因为我想保护我的网关。但是在实现了以下扩展WebSecurityConfigurerAdapter的类之后,*  * 项目抛出java:无法访问javax.servlet.Filter*  * 从Spring Cloud Gateway文档中:Spring Cloud Gateway需要Spring Boot和Spring Webflux提供的Netty运行时。*  * 它不能在传统的Servlet容器中工作,也不能在构建为WAR时工作。扩展WebSecurityConfigurerAdapter是为了基于servlet的应用程序* @Date: Created in 18:11 2022/8/23*/
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate AppUserDetailsService userDetailService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailService);}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {// oauth2 密码模式需要拿到这个beanreturn super.authenticationManagerBean();}/*** @Description 密码模式* @MethodReturnType org.springframework.security.crypto.password.PasswordEncoder* @Author zhiwei Liao* @Date 2021/8/17 15:46**/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(HttpSecurity http) throws Exception {//第一种方式http.formLogin().permitAll().and().authorizeRequests().antMatchers("/oauth/**").permitAll()//不拦截.anyRequest().authenticated().and().logout().permitAll()//退出放行.and().csrf().disable();//关闭CSRF保护//第二种方式
/*        http.cors().and().authorizeRequests().antMatchers("/user/**").hasRole("admin").anyRequest().permitAll()// 添加JWT登录拦截器.and().addFilter(new JWTAuthenticationFilter(authenticationManager()))// 添加JWT鉴权拦截器.addFilter(new JWTAuthorizationFilter(authenticationManager()))// 设置Session的创建策略为:Spring Security不创建HttpSession.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)// 匿名用户访问无权限资源时的异常处理.and().exceptionHandling().authenticationEntryPoint(new JWTAuthenticationEntryPoint()).and().csrf().disable();//关闭CSRF保护*/}@BeanCorsConfigurationSource corsConfigurationSource(){final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();// 注册跨域配置source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());return source;}
}

创建SecurityOauth2Controller

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.controller;import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;/*** @Author: liaozhiwei* @Description: 获取当前登录用户信息* @Date: Created in 09:24 2022/8/24*/
@RestController
@RequestMapping("/securityOauth2")
public class SecurityOauth2Controller {/*** 根据重定向的返回地址获取授权码* @return*/@RequestMapping("/getCodeByCallback")public Object getCodeByCallback() {return "这是一个回调方法(授权码模式:A网站提供一个链接,用户点击后就会跳转到B网站,用户跳转后,B网站会要求用户登录,然后询问是否同意给予A网站授权,用户表示同意,这时B网站就会跳回redirect_uri参数指定的网址,也就是当前这个接口,跳转时,会传回一个授权码";}/*** 回调方法* @return*/@RequestMapping("/redirectUris")public Object redirectUris(HttpServletRequest request) {return "这是一个回调方法,第三方应用授权登录之后,回调到这里,我们可以进行自己系统登录业务,将用户的登录信息录入";}@Autowiredprivate TokenStore tokenService;/*** 获取当前登录用户信息* @param token* @return*/@RequestMapping("/getUserByTokenStore")public Object getUserByTokenStore(@RequestParam("access_token") String token) {OAuth2Authentication oAuth2Authentication =  tokenService.readAuthentication(token);return oAuth2Authentication.getUserAuthentication().getPrincipal();}/*** 获取当前登录用户信息* @param request* @return*/@GetMapping("/getUserByRequest")public Object getUserByRequest(HttpServletRequest request) {String header = request.getHeader("Authorization");String token;if(header!=null){token = header.substring(header.indexOf("bearer") + 7);}else {token = request.getParameter("access_token");}return Jwts.parser().setSigningKey("123123".getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token).getBody();}}

创建AppUserinfoEntity

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.entity;import lombok.Getter;
import lombok.Setter;/*** @Author: liaozhiwei* @Description: 用户的实体类* @Date: Created in 18:24 2022/8/23*/
@Setter
@Getter
public class AppUserinfoEntity {private String userId;private String userName;private String userStatus;private String credential;
}

创建ResultData

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.entity.base;/*** @Author: liaozhiwei* @Description: TODO* @Date: Created in 18:34 2022/8/23*/import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@Data
@NoArgsConstructor
public class ResultData<T> implements Serializable {/*** 状态码*/public boolean status = true;/*** 状态码*/private Integer code = 200;/*** 接口返回信息*/private String msg;/*** 数据对象*/private T data;/*** 初始化一个新创建的 ResultData 对象** @param status 状态码* @param msg    返回内容*/public ResultData(Boolean status, String msg) {this.status = status;this.msg = msg;}/*** 初始化一个新创建的 ResultData 对象** @param status 状态码* @param msg    返回内容* @param data   数据对象*/public ResultData(Boolean status, String msg, T data, Integer code) {this.status = status;this.msg = msg;this.data = data;this.code = code;}public ResultData(T data) {this.data = data;}/*** 返回成功消息** @param msg  返回内容* @param data 数据对象* @return 成功消息*/public static <T> ResultData<T> success(String msg, T data) {return new ResultData<T>(true, msg, data, 200);}/*** 返回成功消息** @param msg 返回内容* @return 成功消息*/public static <T> ResultData<T> success(String msg) {return ResultData.success(msg, null);}/*** 返回成功消息** @return 成功消息*/public static <T> ResultData<T> success() {return ResultData.success(null);}/*** 返回成功数据** @return 成功消息*/public static <T> ResultData<T> success(T data) {return ResultData.success(null, data);}/*** 返回错误消息** @return*/public static <T> ResultData<T> error() {return ResultData.error(null);}/*** 返回错误消息** @param msg 返回内容* @return 警告消息*/public static <T> ResultData<T> error(String msg) {return ResultData.error(msg, null);}/*** 返回错误消息** @param code 状态码* @param msg  返回内容* @return 警告消息*/public static <T> ResultData<T> error(Integer code, String msg) {return new ResultData<T>(false, msg, null, code);}/*** 返回错误消息** @param msg  返回内容* @param data 数据对象* @return 警告消息*/public static <T> ResultData<T> error(String msg, T data) {return new ResultData<T>(false, msg, data, 500);}
}

创建UserInfoFeignService

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.fegin;import com.example.springcloudsecurityoauth2demo.entity.AppUserinfoEntity;
import com.example.springcloudsecurityoauth2demo.entity.base.ResultData;
import com.example.springcloudsecurityoauth2demo.hystrix.UserServiceHystrix;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;/*** @Author: liaozhiwei* @Description: TODO 远程调用用户模块的接口获取用户信息,这里就不写用户模块了* @Date: Created in 18:33 2022/8/23*/
@Component
@FeignClient(name = "user", fallback = UserServiceHystrix.class, path = "/user")
public interface UserInfoFeignService {@GetMapping("/getUserinfoById")ResultData<AppUserinfoEntity> getUserinfoById(@RequestParam("userId") String userId);@GetMapping("/getUserByUserName")ResultData<AppUserinfoEntity> getUserByUserName(@RequestParam("username") String username);}

创建JWTAuthenticationEntryPoint.java

代码如下(示例):

//package com.example.springcloudsecurityoauth2demo.filter;
//
//import com.alibaba.fastjson.JSON;
//import org.springframework.security.core.AuthenticationException;
//import org.springframework.security.web.AuthenticationEntryPoint;
//import javax.servlet.ServletException;
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//import java.io.IOException;
//
//
///**
// * @Author: liaozhiwei
// * @Description: 匿名用户访问资源时无权限的处理
// * @Date: Created in 11:13 2022/8/24
// */
//
//public class JWTAuthenticationEntryPoint implements AuthenticationEntryPoint {//
//  @Override
//  public void commence(HttpServletRequest request, HttpServletResponse response,
//                       AuthenticationException authException) throws IOException, ServletException {//    response.setCharacterEncoding("utf-8");
//    response.setContentType("text/javascript;charset=utf-8");
//    response.getWriter().print(JSON.toJSONString("未登录,没有访问权限"));
//  }
//}

创建JWTAuthenticationFilter.java

代码如下(示例):

//package com.example.springcloudsecurityoauth2demo.filter;
//
//import com.alibaba.fastjson.JSON;
//import com.example.springcloudsecurityoauth2demo.utils.JwtTokenUtil;
//import org.springframework.security.authentication.*;
//import org.springframework.security.core.Authentication;
//import org.springframework.security.core.AuthenticationException;
//import org.springframework.security.core.GrantedAuthority;
//import org.springframework.security.core.userdetails.User;
//import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
//import javax.servlet.FilterChain;
//import javax.servlet.ServletException;
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//import java.io.IOException;
//import java.util.Collection;
//
///**
// * @Author: liaozhiwei
// * @Description: TODO
// * @Date: Created in 16:13 2022/8/24
// */
//
//public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {//
//    private AuthenticationManager authenticationManager;
//
//    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {//        this.authenticationManager = authenticationManager;
//    }
//
//    @Override
//    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {//        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
//                request.getParameter("username"), request.getParameter("password"));
//        return authenticationManager.authenticate(token);
//    }
//
//    @Override
//    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {//        User user = (User) authResult.getPrincipal();
//        // 从User中获取权限信息
//        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
//        // 创建Token
//        String token = JwtTokenUtil.createToken(user.getUsername(), authorities.toString());
//        response.setCharacterEncoding("UTF-8");
//        response.setContentType("application/json; charset=utf-8");
//        // 在请求头里返回创建成功的token
//        // 设置请求头为带有"Bearer "前缀的token字符串
//        response.setHeader("token", JwtTokenUtil.TOKEN_PREFIX + token);
//        response.setContentType("text/json;charset=utf-8");
//        response.getWriter().write(JSON.toJSONString("登录成功"));
//    }
//
//    @Override
//    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {//        String returnData="";
//        if (failed instanceof AccountExpiredException) {//            returnData="账号过期";
//        }else if (failed instanceof BadCredentialsException) {//            returnData="密码错误";
//        }else if (failed instanceof CredentialsExpiredException) {//            returnData="密码过期";
//        }else if (failed instanceof DisabledException) {//            returnData="账号不可用";
//        }else if (failed instanceof LockedException) {//            returnData="账号锁定";
//        }else if (failed instanceof InternalAuthenticationServiceException) {//            returnData="用户不存在";
//        }else{//            returnData="未知异常";
//        }
//
//        response.setContentType("text/json;charset=utf-8");
//        response.getWriter().write(JSON.toJSONString(returnData));
//    }
//}

创建JWTAuthorizationFilter.java

代码如下(示例):

//package com.example.springcloudsecurityoauth2demo.filter;
//
//import com.example.springcloudsecurityoauth2demo.utils.JwtTokenUtil;
//import org.apache.commons.lang3.StringUtils;
//import org.springframework.security.authentication.AuthenticationManager;
//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
//import org.springframework.security.core.authority.SimpleGrantedAuthority;
//import org.springframework.security.core.context.SecurityContextHolder;
//import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
//import javax.servlet.FilterChain;
//import javax.servlet.ServletException;
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//import java.io.IOException;
//import java.util.ArrayList;
//import java.util.Collection;
//
///**
// * @Author: liaozhiwei
// * @Description: TODO
// * @Date: Created in 16:13 2022/8/24
// */
//
//public class JWTAuthorizationFilter extends BasicAuthenticationFilter {//
//
//    public JWTAuthorizationFilter(AuthenticationManager authenticationManager) {//        super(authenticationManager);
//    }
//
//    @Override
//    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {//        String tokenHeader = request.getHeader(JwtTokenUtil.TOKEN_HEADER);
//        // 若请求头中没有Authorization信息 或是Authorization不以Bearer开头 则直接放行
//        if (tokenHeader == null || !tokenHeader.startsWith(JwtTokenUtil.TOKEN_PREFIX)){//            filterChain.doFilter(request, response);
//            return;
//        }
//        // 若请求头中有token 则调用下面的方法进行解析 并设置认证信息
//        SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader));
//        super.doFilterInternal(request, response, filterChain);
//    }
//
//    /*
//     * 从token中获取用户信息并新建一个token
//     * @param tokenHeader 字符串形式的Token请求头
//     * @return 带用户名和密码以及权限的Authentication
//     */
//    private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) {//        // 去掉前缀 获取Token字符串
//        String token = tokenHeader.replace(JwtTokenUtil.TOKEN_PREFIX, "");
//        // 从Token中解密获取用户名
//        String username = JwtTokenUtil.getUsername(token);
//        // 从Token中解密获取用户角色
//        String role = JwtTokenUtil.getUserRole(token);
//        // 将[ROLE_XXX,ROLE_YYY]格式的角色字符串转换为数组
//        String[] roles = StringUtils.strip(role, "[]").split(", ");
//        Collection<SimpleGrantedAuthority> authorities=new ArrayList<>();
//        for (String s:roles)
//        {//            authorities.add(new SimpleGrantedAuthority(s));
//        }
//        if (username != null)
//        {//            return new UsernamePasswordAuthenticationToken(username, null,authorities);
//        }
//        return null;
//    }
//}

创建UserServiceHystrix

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.hystrix;/*** @Author: liaozhiwei* @Description: TODO* @Date: Created in 18:37 2022/8/23*/
import com.example.springcloudsecurityoauth2demo.entity.AppUserinfoEntity;
import com.example.springcloudsecurityoauth2demo.entity.base.ResultData;
import com.example.springcloudsecurityoauth2demo.fegin.UserInfoFeignService;
import org.springframework.stereotype.Component;/*** @author zhiwei Liao* @version 1.0* @Description* @Date 2021/8/17 15:25*/@Component
public class UserServiceHystrix implements UserInfoFeignService {@Overridepublic ResultData<AppUserinfoEntity> getUserinfoById(String userId) {return null;}@Overridepublic ResultData<AppUserinfoEntity> getUserByUserName(String username) {return null;}
}

创建JwtCAProperties

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.properties;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/*** @Author: liaozhiwei* @Description: 读取配置文件中的属性配置* @Date: Created in 19:10 2022/8/23*/@Data
@ConfigurationProperties(prefix = "auth.jwt")
public class JwtCAProperties {/*** 证书名称*/private String keyPairName;/*** 证书别名*/private String keyPairAlias;/*** 证书私钥*/private String keyPairSecret;/*** 证书存储密钥*/private String keyPairStoreSecret;}

创建AppUserDetailsService

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.service;import com.example.springcloudsecurityoauth2demo.entity.AppUserinfoEntity;
import com.example.springcloudsecurityoauth2demo.entity.base.ResultData;
import com.example.springcloudsecurityoauth2demo.fegin.UserInfoFeignService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.authority.AuthorityUtils;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;/*** @Author: liaozhiwei* @Description: TODO* @Date: Created in 18:13 2022/8/23*/
@Service
@Slf4j
public class AppUserDetailsService implements UserDetailsService {@Autowired@Lazyprivate PasswordEncoder passwordEncoder;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {//第一种方式:写死直接返回String password = passwordEncoder.encode("123456");System.out.println(password);return new User("liaozhiwei",password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));//AuthorityUtils.commaSeparatedStringToAuthorityList("admin")用来为用户分配权限
/*        // 第二种方式:  查数据库获取用户信息   rpc调用// 加载用户信息if (StringUtils.isEmpty(username)) {log.warn("用户登陆用户名为空:{}", username);throw new UsernameNotFoundException("用户名不能为空");}AppUserinfoEntity userUserinfo = getByUserName(username);if (null == userUserinfo) {log.warn("根据用户名没有查询到对应的用户信息:{}", username);}log.info("根据用户名:{}获取用户登陆信息:{}", username, userUserinfo);// 用户信息的封装 implements UserDetailsUserInfoDetails memberDetails = new UserInfoDetails(userUserinfo);return memberDetails;*/}@Autowiredprivate UserInfoFeignService userInfoFeignService;public AppUserinfoEntity getByUserName(String username) {// fegin获取用户信息ResultData<AppUserinfoEntity> resultData = userInfoFeignService.getUserByUserName(username);return resultData.getData();}
}

创建UserInfoDetails

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.service;/*** @Author: liaozhiwei* @Description: TODO* @Date: Created in 19:04 2022/8/23*/
import com.example.springcloudsecurityoauth2demo.entity.AppUserinfoEntity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Arrays;
import java.util.Collection;/*** @Author: liaozhiwei* @Description: TODO* @Date: Created in 19:13 2022/8/23*/
public class UserInfoDetails implements UserDetails {private AppUserinfoEntity userUserinfo;public UserInfoDetails(AppUserinfoEntity userUserinfo) {this.userUserinfo = userUserinfo;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {//返回当前用户的权限  BRAC   user  role  authorityreturn Arrays.asList(new SimpleGrantedAuthority("TEST"));}// 获取用户密码(凭证)@Overridepublic String getPassword() {return userUserinfo.getCredential();}// 获取用户名@Overridepublic String getUsername() {return userUserinfo.getUserName();}// 判断帐号是否已经过期@Overridepublic boolean isAccountNonExpired() {return true;}// 判断帐号是否已被锁定@Overridepublic boolean isAccountNonLocked() {return true;}// 判断用户凭证是否已经过期@Overridepublic boolean isCredentialsNonExpired() {return true;}// 判断用户帐号是否已启用@Overridepublic boolean isEnabled() {return !userUserinfo.getUserStatus().equals("FREEZE");}public AppUserinfoEntity getUserUserinfo() {return userUserinfo;}}

创建JwtTokenUtil

代码如下(示例):

package com.example.springcloudsecurityoauth2demo.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/*** @Author: liaozhiwei* @Description: TODO* @Date: Created in 19:13 2022/8/24*/
public class JwtTokenUtil {// Token请求头public static final String TOKEN_HEADER = "Authorization";// Token前缀public static final String TOKEN_PREFIX = "Bearer ";// 签名主题public static final String SUBJECT = "app";// 过期时间public static final long EXPIRITION =  24 * 60 * 60 ;// 应用密钥public static final String APPSECRET_KEY = "123123";// 角色权限声明private static final String ROLE_CLAIMS = "role";/*** 生成Token*/public static String createToken(String username,String role) {Map<String,Object> map = new HashMap<>();map.put(ROLE_CLAIMS, role);String token = Jwts.builder().setSubject(username).setClaims(map).claim("username",username).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + EXPIRITION)).signWith(SignatureAlgorithm.HS256, APPSECRET_KEY).compact();return token;}/*** 校验Token*/public static Claims checkJWT(String token) {try {final Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();return claims;} catch (Exception e) {e.printStackTrace();return null;}}/*** 从Token中获取username*/public static String getUsername(String token){Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();return claims.get("username").toString();}/*** 从Token中获取用户角色*/public static String getUserRole(String token){Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();return claims.get("role").toString();}/*** 校验Token是否过期*/public static boolean isExpiration(String token){Claims claims = Jwts.parser().setSigningKey(APPSECRET_KEY).parseClaimsJws(token).getBody();return claims.getExpiration().before(new Date());}
}

验证Spring Cloud Security Oauth2是否工作

首先要获取access_token,然后根据access_token认证授权

授权码模式

获取授权码

浏览器请求:http://127.0.0.1:8807/oauth/authorize?response_type=code&client_id=client
重定向为:http://127.0.0.1:8807/login
输入
用户名:liaozhiwei
密码:123456
如下图(示例):

授权登录之后会进行回调获取授权码

如下图(示例):

填入授权码code获取获取access_token

发起请求:http://127.0.0.1:8807/oauth/token?grant_type=authorization_code&client_id=client&client_secret=client_secret&code=12PVmF
如下图(示例):

password模式

http://127.0.0.1:8807/oauth/token?username=liaozhiwei&password=123456&grant_type=password&client_id=client&client_secret=client_secret&scope=all
如下图(示例):

刷新令牌获取access_token

http://127.0.0.1:8807/oauth/token?grant_type=refresh_token&client_id=client&client_secret=client_secret&refresh_token=
如下图(示例):

请求(示例):

http://127.0.0.1:8807/oauth/token?grant_type=refresh_token&client_id=client&client_secret=client_secret&refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJsaWFvemhpd2VpIiwic2NvcGUiOlsiYWxsIl0sImF0aSI6ImZlNzJhYTE2LTM2M2EtNDFlNS05YWM2LTY0MDhkYjIzZWMyMCIsImFkZGl0aW9uYWxJbmZvIjp7InVzZXJOYW1lIjoibGlhb3poaXdlaSJ9LCJleHAiOjE2NjIyMTkzNjcsImF1dGhvcml0aWVzIjpbImFkbWluIl0sImp0aSI6IjFkNjRiMGI5LTkwNTQtNGMzYi05OWY1LTJjYzVjZGIxMTk2NSIsImNsaWVudF9pZCI6ImNsaWVudCJ9.cp6KF2XQJlNBRQTJXSvPpKh0t7jIAcJ9KegA60QIEK7dUYnMMf9b9I5Zu8AlmcQAq0tGGNTTLm1Wo42fYOWCElotRYDx-465kemhcuf-nHdGQ-qXDYMuhOKO5hlG1eajMD1ceoPK71dAxvEMRWAC5hk3_PmxlPIyaO-mDQJB3PhaDjEVNGhRncp7u5-UkPL3gZg1D9r-Yk1gDB9R1Qe7UDv0oBa_u07Vm1Q8i8tXnm6__6Xi2E16HBP0c872jc6voG2LCtcA5LMoPTHQlg3xAPodTuF7ncy188vXPAUzHf2Cp8ITH2lpJ68Jl0XQq8kz9vfv3r1_vK9_mbVAiys1UQ

发起请求使用access_token进行授权获取登录用户信息

http://127.0.0.1:8807/securityOauth2/getUserByTokenStore?access_token=
如下图(示例):
到这里其实已经可以验证我们通过授权码和密码模式获取access_token,然后通过access_token获取登录用户的消息了,当然还有更多的验证在代码里面已经实现了,这里我只对获取登录用户进行演示校验过程

创建spring-cloud-security-oauth2-sso-client-demo项目(实现单点登录)

项目代码:https://gitee.com/java_wxid/java_wxid/tree/master/demo/spring-cloud-security-oauth2-sso-client-demo
项目结构如下图(示例):

修改pom.xml文件

如下(示例):

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion><groupId>com.example</groupId><artifactId>spring-cloud-security-oauth2-sso-client-demo</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-cloud-security-oauth2-sso-client-demo</name><description>Demo project for Spring Boot</description><!--    属性配置--><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><!--引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系--><spring.boot.version>2.3.12.RELEASE</spring.boot.version><spring.cloud.version>Hoxton.SR12</spring.cloud.version><spring.cloud.alibaba.version>2.2.7.RELEASE</spring.cloud.alibaba.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--        代表web模块,在这个模块中含了许多JAR包,有spring相关的jar,内置tomcat服务器,jackson等,这些web项目中常用的的功能都会自动引入--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Alibaba Nacos 配置 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--        在SpringBoot 2.4.x的版本之后,对于bootstrap.properties/bootstrap.yaml配置文件(我们合起来成为Bootstrap配置文件)的支持,其实这个jar包里什么都没有,就只有一个标识类Marker,用来标识要开启Bootstrap配置文件的支持,由于父类用了2.5.6版本需要导入如下的依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId><version>3.1.0</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId></dependency><!--JWT依赖--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><!--引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系--><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>${spring.boot.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring.cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring.cloud.alibaba.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

创建bootstrap.yml文件

代码如下(示例):

#bootstrap.yml优先级比application.yml优先级高
spring:#prefix−{spring.profile.active}.${file-extension}#nacos会根据当前环境去拼接配置名称查找相应配置文件,#示例:{spring.application.name}-{spring.profiles.active}-{spring.cloud.nacos.config.file-extension}#获取到值:nacos-autoconfig-service-dev.ymlprofiles:#开发环境dev,测试环境test,生产环境prodactive: devapplication:#配置应用的名称,用于获取配置name: security-oauth2-sso-clientmain:allow-bean-definition-overriding: truecloud:nacos:discovery:# 服务注册地址server-addr: ip:8848config:#nacos配置中心地址server-addr: ip:8848#配置中心的命名空间idnamespace: 9e50b6d9-6c3d-4e7a-b701-10f085e4b98d#配置分组,默认没有也可以group: DEFAULT_GROUP#配置文件后缀,用于拼接配置配置文件名称,目前只支持yaml和propertiesfile-extension: yaml#配置自动刷新refresh-enabled: true#配置文件的前缀,默认是application.name的值,如果配了prefix,就取prefix的值#prefix: nacos-autoconfig-service-${spring.profile.active}# 配置编码encode: UTF-8username: nacospassword: nacos

修改application.properties文件

代码如下(示例):

server.port=8808
server.servlet.session.cookie.name=OAUTH2-CLIENT-SESSIONID${server.port}
oauth2-server-url: http://127.0.0.1:8807
security.oauth2.client.client-id=client
security.oauth2.client.use-current-uri=false
security.oauth2.client.client-secret=client_secret
security.oauth2.client.user-authorization-uri=${oauth2-serverurl}/oauth/authorize
security.oauth2.client.access-token-uri=${oauth2-server-url}/oauth/token
security.oauth2.resource.jwt.key-uri=${oauth2-server-url}/oauth/token_key

修改SpringCloudSecurityOauth2SsoClientDemoApplication

代码如下(示例):

package com.luban.oauth2ssoclientdemo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
/*@EnableOAuth2Sso单点登录的原理简单来说就是:标注有@EnableOAuth2Sso的OAuth2 Client应用在通过某种
OAuth2授权流程获取访问令牌后(一般是授权码流程),通过访问令牌访问userDetails用户明细这个受保护资源服务,
获取用户信息后,将用户信息转换为Spring Security上下文中的认证后凭证Authentication,从而完成标注有
@EnableOAuth2Sso的OAuth2 Client应用自身的登录认证的过程。整个过程是基于OAuth2的SSO单点登录*/
@EnableOAuth2Sso
@EnableDiscoveryClient
public class SpringCloudSecurityOauth2SsoClientDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringCloudSecurityOauth2SsoClientDemoApplication.class, args);}}

创建UserController

代码如下(示例):

package com.luban.oauth2ssoclientdemo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @Author: liaozhiwei* @Description: TODO* @Date: Created in 09:24 2022/8/24*/
@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/testCallback")public Object testCallback() {return "";}
}

校验请求是否有到授权服务器进行授权

浏览器发起请求:http://localhost:8808/user/getUserByAuthentication
重定向到登录页面:
输入
用户名:liaozhiwei
密码:123456
如下图(示例):

授权登录之会进行回调,返回授权码

如下图(示例):

拿到授权码获取access_token

http://127.0.0.1:8807/oauth/token?grant_type=authorization_code&client_id=client&client_secret=client_secret&code=fj7ivJ
如下图(示例):

到这里为止,可以发现单点登录也基本校验成功了

【java_wxid项目】【第七章】【Spring Cloud Security Oauth2集成】相关推荐

  1. gateway oauth2 对称加密_深入理解Spring Cloud Security OAuth2及JWT

    因项目需要,需要和三方的oauth2服务器进行集成.网上关于spring cloud security oauth2的相关资料,一般都是讲如何配置,而能把这块原理讲透彻的比较少,这边自己做一下总结和整 ...

  2. 玩转Spring Cloud Security OAuth2身份认证扩展——电话号码+验证码认证

    在程序的认证过程中,除了常规的用户名和密码方式(可以参考深入理解Spring Cloud Security OAuth2身份认证),也经常会出现电话号码+密码的方式:电话号码+验证码的方式:或者第三方 ...

  3. Spring Cloud Security OAuth2结合网关

    文章目录 一.需求分析 二.服务搭建 2.1 注册中心 Eureka 搭建 2.2 网关 Zuul 搭建 2.2.1 转发明文token给微服务 2.2.2 微服务处理 token 2.2.3 Spr ...

  4. 【java_wxid项目】【第十六章】【Spring Cloud Alibaba Sentinel集成】

    主项目链接:https://gitee.com/java_wxid/java_wxid 项目架构及博文总结: 点击:[使用Spring Boot快速构建应用] 点击:[使用Spring Cloud O ...

  5. 《深入理解 Spring Cloud 与微服务构建》第十六章 Spring Boot Security 详解

    <深入理解 Spring Cloud 与微服务构建>第十六章 Spring Boot Security 详解 文章目录 <深入理解 Spring Cloud 与微服务构建>第十 ...

  6. 《深入理解 Spring Cloud 与微服务构建》第三章 Spring Cloud

    <深入理解 Spring Cloud 与微服务构建>第三章 Spring Cloud 文章目录 <深入理解 Spring Cloud 与微服务构建>第三章 Spring Clo ...

  7. java B2B2C springmvc mybatis电子商务平台源码-Spring Cloud Security

    一.SpringCloud Security简介           Spring Cloud Security提供了一组原语,用于构建安全的应用程序和服务,而且操作简便.可以在外部(或集中)进行大量 ...

  8. Spring Cloud Security:Oauth2实现单点登录

    摘要 Spring Cloud Security 为构建安全的SpringBoot应用提供了一系列解决方案,结合Oauth2可以实现单点登录功能,本文将对其单点登录用法进行详细介绍. 单点登录简介 单 ...

  9. Spring Cloud Security:Oauth2结合JWT使用

    摘要 Spring Cloud Security 为构建安全的SpringBoot应用提供了一系列解决方案,结合Oauth2还可以实现更多功能,比如使用JWT令牌存储信息,刷新令牌功能,本文将对其结合 ...

最新文章

  1. BCH升级日期将至,社区组织开始为11月“硬分叉”做准备
  2. Unity3D中暂停时的动画及粒子效果实现
  3. linux冒泡算法程序,用蛮力法解决冒泡排序 - linux-tao的个人空间 - OSCHINA - 中文开源技术交流社区...
  4. 安装node和pm2
  5. python判断路径是文件还是文件夹_python之判断是否是目录或文件
  6. luogu 3806
  7. Bootstrap学习笔记01【快速入门、栅格布局】
  8. opencv 手部识别_手势识别结合到VR头显中,有哪些难点?
  9. html-css练习题 (注册表单)
  10. python 怎么样才有output_[学]Python用户手册笔记_4_Input and Output
  11. 点击键盘上的“Next”button实现文本框焦点跳转
  12. ASP.NET MVC HandleErrorAttribute 和 远程链接
  13. 二级c语言上机题库下载,二级C语言上机题库(全).doc
  14. Android WideVine
  15. 今天过节,摔杯,逼宫,吃瓜吧?
  16. PostMan 快快走开, ApiFox 来了, ApiFox 强大的Api调用工具
  17. 免费合并多个PDF文件
  18. 【Django | 开发】面试招聘网站(增加csv,excel导出企业域账号集成日志管理功能)
  19. SQLAlchemy批量操作数据
  20. Web前端开发技术:实验14-16

热门文章

  1. java lucence使用案例_2、Lucene 最简单的使用(小例子)
  2. 虚拟机启动时出现“已启用侧通道缓解”的解决方法
  3. Altium Designer AD 2019最新各种元器件的原理图库、封装库、集成库、3D库,总量达四千多个,分类齐全。
  4. SNS网站Feed功能设计
  5. java字符串去重,精心整理
  6. Python队列|一文看懂python队列的几种类型
  7. 从零开始建立 EMQ X MQTT 服务器 的 K8S 集群
  8. “凛冬“已至二手车,天天拍车还能“守望“多久?
  9. 华为云服务之网络服务
  10. 科沃斯扫地机器人哪个型号最实用_扫地机器人哪个型号好_智能扫地机功能-科沃斯机器人官网-科沃斯机器人官网...