文章目录

  • 一、前言
  • 二、什么是OAuth2?
  • 三、应用场景
  • 四、三部分
  • 五、四种授权模式
    • 1. 授权码模式(authorization code)
    • 2. 简化模式(implicit)
    • 3. 密码模式(resource owner password credentials)
    • 4. 客户端模式(client credentials)
  • 六、编程
    • 1、授权服务
      • a、引入依赖
      • b、`application.yml`配置
      • c、Security 核心配置类
      • d、配置生成token存储
      • e、自定义JWT返回信息
      • f、配置添加JWT额外信息
      • j、授权服务器配置
    • 2、资源服务
      • a、引入依赖
      • b、`application.yml`配置
      • c、配置生成token存储
      • d、资源服务器配置
      • e、测试api
    • 3、第三方应用
      • a、引入依赖
      • b、`application.yml`配置
      • c、index.html
      • d、测试api
      • e、Token获取和定时刷新任务
    • 4、测试
  • 七、本文案例demo源码

一、前言

  1. Spring Security(1) 入门体验
  2. Spring Security(2) 自定义登录认证
  3. Spring Security(3) 动态url权限控制
  4. Spring Security(4) 整合JWT

二、什么是OAuth2?

OAuth 是一个开放标准,允许用户授权第三方应用访问他们在某网站上存储的私密资源(ex:用户昵称、头像等),在这个过程中无需将用户名和密码提供给第三方应用。

即以令牌token换资源信息数据。

三、应用场景

第三方应用授权登录,ex:QQ、微信授权登录

四、三部分

  1. 第三方应用
  2. 授权服务器
  3. 资源服务器

五、四种授权模式

1. 授权码模式(authorization code)

常用模式,主流第三方验证

  1. 第三方应用引导用户跳转到授权服务器的授权页面,授权后,授权服务器生成认证码code,然后携带code重定向返回
  2. 第三方应用使用认证码code和自身应用凭证(app_id和app_secret)到授权服务器换取访问令牌(access_token)和更新令牌(refresh_token)
  3. 第三方应用使用访问令牌(access_token)去资源服务器获取资源信息(ex:用户昵称,头像等)

2. 简化模式(implicit)

适用于只有前端,前端单方面即可完成

  1. 用户在第三方网站上点击授权跳转授权服务器,授权后,携带访问令牌(access_token)返回第三方网站
  2. 第三方网站再携带 access_token 去资源服务器获取用户信息(昵称,头像等)

3. 密码模式(resource owner password credentials)

适用于自家公司搭建的授权服务器,给兄弟公司用

直接使用用户名/密码从授权服务器获取访问令牌(access_token)

4. 客户端模式(client credentials)

此过程中无需用户参与,一般用于提供给完全信任的服务端服务

客户端请求就返回访问令牌(access_token)

六、编程

参考 https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzI1NDY0MTkzNQ==&action=getalbum&album_id=1319833457266163712
^_^建议跟着这个大佬的OAuth2系列学习下^_^

项目 端口 备注
auth 10010 授权服务器
client 10020 第三方应用
user 10030 资源服务器

oauth2.sql

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- 建库
create database if not exists oauth2 default charset = utf8mb4;
use oauth2;-- ----------------------------
-- Table structure for oauth_client_details
-- ----------------------------
DROP TABLE IF EXISTS `oauth_client_details`;
CREATE TABLE `oauth_client_details`  (`client_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户端ID,唯一标识',`client_secret` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '客户端访问秘钥,BCryptPasswordEncoder加密算法加密',`resource_ids` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '可访问资源id(英文逗号分隔)',`scope` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '授权范围(英文逗号分隔)',`authorized_grant_types` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '授权类型(英文逗号分隔)',`web_server_redirect_uri` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '重定向uri',`authorities` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '@PreAuthorize(\"hasAuthority(\'admin\')\")可以在方法上标志 用户或者说client 需要说明样的权限\r\n\n\n指定客户端所拥有的Spring Security的权限值\r\n(英文逗号分隔)',`access_token_validity` int(11) NOT NULL COMMENT '令牌有效期(单位:秒)',`refresh_token_validity` int(11) NOT NULL COMMENT '刷新令牌有效期(单位:秒)',`additional_information` varchar(4096) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '预留字段,在Oauth的流程中没有实际的使用(JSON格式数据)',`autoapprove` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '设置用户是否自动Approval操作, 默认值为 \'false\'\r\n可选值包括 \'true\',\'false\', \'read\',\'write\'.\r\n该字段只适用于grant_type=\"authorization_code\"的情况,当用户登录成功后,若该值为\'true\'或支持的scope值,则会跳过用户Approve的页面, 直接授权',`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`client_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT INTO `oauth_client_details` VALUES ('zq_app_id', '$2a$10$kdh16TzZoILQmaC4VkKdq.Ah2/u4LBbNJ7lpTqC8NXZVXKiu2LnVa', 'res1', 'all', 'authorization_code,refresh_token', 'http://127.0.0.1:10020/index.html', NULL, 3600, 259200, NULL, NULL, '2022-04-02 09:31:10', '2022-04-02 09:34:22');SET FOREIGN_KEY_CHECKS = 1;

1、授权服务

a、引入依赖
<!--Spring Security -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency><!-- OAuth2 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId><!-- 指明版本,解决redis存储出现的问题:java.lang.NoSuchMethodError: org.springframework.data.redis.connection.RedisConnection.set([B[B)V --><version>2.3.3.RELEASE</version>
</dependency><!-- 数据库相关 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.40</version>
</dependency>
b、application.yml配置
server:port: 10010spring:application:name: auth# MySQL数据源配置datasource:url: jdbc:mysql://127.0.0.1:3306/oauth2?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF8&zeroDateTimeBehavior=convertToNull&useSSL=false # MySQL在高版本需要指明是否进行SSL连接 解决则加上 &useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.jdbc.Driver
c、Security 核心配置类
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}/*** 配置用户 -- 校验用户* 校验客户端见 {@link com.zhengqing.auth.config.AuthorizationServerConfig#configure(org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer)}*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication()// admin.withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("admin")// test.and().withUser("test").password(new BCryptPasswordEncoder().encode("123456")).roles("test");}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** 权限配置*/@Overrideprotected void configure(HttpSecurity http) throws Exception {// 禁用CSRF 表单登录http.csrf().disable().formLogin();}}
d、配置生成token存储
@Configuration
public class AccessTokenConfig {//    @Resource
//    RedisConnectionFactory redisConnectionFactory;/*** JWT 字符串生成时所需签名*/private final String SIGNING_KEY = "zhengqingya";@BeanTokenStore tokenStore() {// 内存
//        return new InMemoryTokenStore();// redis
//        return new RedisTokenStore(this.redisConnectionFactory);// jwt -- 无状态登录,服务端不需要保存信息return new JwtTokenStore(this.jwtAccessTokenConverter());}/*** 实现将用户信息和 JWT 进行转换(将用户信息转为 jwt 字符串,或者从 jwt 字符串提取出用户信息)*/@BeanJwtAccessTokenConverter jwtAccessTokenConverter() {// 原生jwt
//        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();// 自定义JWT返回信息JwtAccessTokenConverter converter = new MyJwt();converter.setSigningKey(this.SIGNING_KEY);return converter;}}
e、自定义JWT返回信息
public class MyJwt extends JwtAccessTokenConverter {@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {Map<String, Object> additionalInformation = new LinkedHashMap<>();Map<String, Object> info = new LinkedHashMap<>();info.put("author", "zhengqingya");info.put("gitee", "https://gitee.com/zhengqingya");info.put("user", SecurityContextHolder.getContext().getAuthentication().getPrincipal());additionalInformation.put("info", info);((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInformation);return super.enhance(accessToken, authentication);}}
f、配置添加JWT额外信息
@Component
public class CustomAdditionalInformation implements TokenEnhancer {@Overridepublic OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {Map<String, Object> info = accessToken.getAdditionalInformation();info.put("author", "zhengqingya");((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);return accessToken;}}
j、授权服务器配置
@Configuration
// 开启授权服务器的自动化配置
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {@ResourceTokenStore tokenStore;@ResourceClientDetailsService clientDetailsService;@ResourceDataSource dataSource;@ResourceJwtAccessTokenConverter jwtAccessTokenConverter;@ResourceCustomAdditionalInformation customAdditionalInformation;/*** {@link com.zhengqing.auth.config.SecurityConfig#authenticationManagerBean()}*/@ResourceAuthenticationManager authenticationManager;@BeanClientDetailsService jdbcClientDetailsService() {return new JdbcClientDetailsService(this.dataSource);}/*** 配置令牌端点的安全约束* 即这个端点谁能访问,谁不能访问* checkTokenAccess: 指一个 Token 校验的端点,这个端点我们设置为可以直接访问(当资源服务器收到 Token 之后,需要去校验 Token 的合法性,就会访问这个端点)*/@Overridepublic void configure(AuthorizationServerSecurityConfigurer security) throws Exception {security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients();}/*** 配置客户端的详细信息 -- 校验客户端* 校验用户见 {@link com.zhengqing.auth.config.SecurityConfig#configure(org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder)}*/
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {//        clients.inMemory()
//                // id
//                .withClient("zq_app_id")
//                // secret
//                .secret(new BCryptPasswordEncoder().encode("zq_app_secret"))
//                // 资源id
//                .resourceIds("res1")
//                // 授权类型 -- 授权码模式
//                .authorizedGrantTypes("authorization_code", "refresh_token")
//                // 授权范围
//                .scopes("all")
//                // 重定向uri
//                .redirectUris("http://127.0.0.1:10020/index.html");
//    }@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.withClientDetails(this.jdbcClientDetailsService());}/*** 配置令牌的访问端点和令牌服务* 授权码和令牌有什么区别?授权码是用来获取令牌的,使用一次就失效,令牌则是用来获取资源的*/@Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {// 配置授权码的存储endpoints.authorizationCodeServices(this.authorizationCodeServices()).authenticationManager(this.authenticationManager)// 配置令牌的存储.tokenServices(this.tokenServices());}/*** 配置授权码的存储*/@BeanAuthorizationCodeServices authorizationCodeServices() {// 内存return new InMemoryAuthorizationCodeServices();}/*** 配置 Token 的一些基本信息*/@BeanAuthorizationServerTokenServices tokenServices() {DefaultTokenServices services = new DefaultTokenServices();services.setClientDetailsService(this.clientDetailsService);// 是否支持刷新services.setSupportRefreshToken(true);// 存储位置services.setTokenStore(this.tokenStore);// 有效期
//        services.setAccessTokenValiditySeconds(60 * 60 * 1);// 刷新token的有效期 -- 当token块过期的时候,需要获取一个新的token,在获取新token的时候,需要一个凭证信息,这个凭证信息不是旧的 Token,而是另外一个 refresh_token,这个 refresh_token 也是有有效期的。
//        services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 3);// 注入“jwt添加额外信息”相关实例TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();tokenEnhancerChain.setTokenEnhancers(Arrays.asList(this.jwtAccessTokenConverter, this.customAdditionalInformation));services.setTokenEnhancer(tokenEnhancerChain);return services;}}

2、资源服务

a、引入依赖
 <!-- Spring Security -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency><!-- OAuth2 -->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
b、application.yml配置
server:port: 10030spring:application:name: user
c、配置生成token存储
@Configuration
public class AccessTokenConfig {//    @Resource
//    RedisConnectionFactory redisConnectionFactory;/*** JWT 字符串生成时所需签名*/private final String SIGNING_KEY = "zhengqingya";@BeanTokenStore tokenStore() {// 内存
//        return new InMemoryTokenStore();// redis
//        return new RedisTokenStore(this.redisConnectionFactory);// jwt -- 无状态登录,服务端不需要保存信息return new JwtTokenStore(this.jwtAccessTokenConverter());}/*** 实现将用户信息和 JWT 进行转换(将用户信息转为 jwt 字符串,或者从 jwt 字符串提取出用户信息)*/@BeanJwtAccessTokenConverter jwtAccessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey(this.SIGNING_KEY);return converter;}}
d、资源服务器配置
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {@ResourceTokenStore tokenStore;/*** 配置一个 RemoteTokenServices 的实例,因为资源服务器和授权服务器是分开的;* 如果资源服务器和授权服务器是放在一起的,就不需要配置 RemoteTokenServices 了。* 校验客户端见 {@link com.zhengqing.auth.config.AuthorizationServerConfig#configure(org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer)}* <p>* 当用户来资源服务器请求资源时,会携带上一个 access_token,通过这里的配置,就能够校验出 token 是否正确等。*/
//    @Bean
//    RemoteTokenServices tokenServices() {//        RemoteTokenServices services = new RemoteTokenServices();
//        // access_token 的校验地址
//        services.setCheckTokenEndpointUrl("http://127.0.0.1:10010/oauth/check_token");
//        services.setClientId("zq_app_id");
//        services.setClientSecret("zq_app_secret");
//        return services;
//    }/*** 自动调用 JwtAccessTokenConverter 将 jwt 解析出来,jwt 里边就包含了用户的基本信息,所以就不用上面一样远程校验 access_token 了。*/@Overridepublic void configure(ResourceServerSecurityConfigurer resources) throws Exception {resources.resourceId("res1").tokenStore(this.tokenStore);}/*** 配置资源的拦截规则*/@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/**").hasRole("admin").anyRequest().authenticated();}
}
e、测试api
@RestController
public class HelloController {@GetMapping("/hello")public String hello() {return "hello";}@GetMapping("/admin/hello")public String admin() {return "admin";}
}

3、第三方应用

a、引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
b、application.yml配置
server:port: 10020spring:application:name: client
c、index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>APP</title>
</head>
<body>
Hello World! <br/><!--点击超链接实现第三方登录client_id 客户端 ID,根据我们在授权服务器中的实际配置填写。response_type 表示响应类型,这里是 code 表示响应一个授权码。redirect_uri 表示授权成功后的重定向地址,这里表示回到第三方应用的首页。scope 表示授权范围。
-->
<a href="http://127.0.0.1:10010/oauth/authorize?client_id=zq_app_id&response_type=code&scope=all&redirect_uri=http://127.0.0.1:10020/index.html">第三方登录</a><h1 th:text="${msg}"></h1></body>
</html>
d、测试api
@Slf4j
@Controller
@RequestMapping("")
@Api(tags = {"测试api"})
public class TestController {@Resourceprivate TokenTask tokenTask;@GetMapping("/index.html")public String hello(String code, Model model) {model.addAttribute("msg", this.tokenTask.getData(code));return "index";}}
e、Token获取和定时刷新任务
@Slf4j
@Component
@SessionScope
@EnableScheduling
public class TokenTask {public String access_token = "";public String refresh_token = "";public String getData(String code) {if (StringUtils.isBlank(code)) {return "未认证";}if (StringUtils.isBlank(this.access_token)) {/*** 如果 code 不为 null,标识是通过授权服务器重定向到这个地址来的* 根据拿到的 code 去获取 Token*/MultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("code", code);map.add("client_id", "zq_app_id");map.add("client_secret", "zq_app_secret");map.add("redirect_uri", "http://127.0.0.1:10020/index.html");map.add("grant_type", "authorization_code");Map<String, String> authResponseMap = new RestTemplate().postForObject("http://127.0.0.1:10010/oauth/token", map, Map.class);log.info("authResponse: {}", JSON.toJSONString(authResponseMap));this.access_token = authResponseMap.get("access_token");this.refresh_token = authResponseMap.get("refresh_token");return this.loadDataFromResServer();} else {return this.loadDataFromResServer();}}/*** 加载资源服务器数据*/private String loadDataFromResServer() {try {HttpHeaders headers = new HttpHeaders();headers.add("Authorization", "Bearer " + this.access_token);HttpEntity<Object> httpEntity = new HttpEntity<>(headers);ResponseEntity<String> entity = new RestTemplate().exchange("http://127.0.0.1:10030/admin/hello", HttpMethod.GET, httpEntity, String.class);return entity.getBody();} catch (RestClientException e) {log.error("加载资源服务器数据:", e);return "未加载";}}/*** 刷新令牌定时任务* 每隔 55 分钟去刷新一下 access_token(access_token 有效期是 60 分钟)。*/
//    @Scheduled(cron = "0 */55 * * * ?")@Scheduled(cron = "*/30 * * * * ?") // 每隔30秒public void tokenTask() {log.info("<<<<<< 刷新令牌定时任务 Start: 【{}】 >>>>>>", DateTime.now());if (StringUtils.isBlank(this.refresh_token)) {return;}MultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("client_id", "zq_app_id");map.add("client_secret", "zq_app_secret");map.add("grant_type", "refresh_token");map.add("refresh_token", this.refresh_token);Map<String, String> authResponseMap = new RestTemplate().postForObject("http://127.0.0.1:10010/oauth/token", map, Map.class);log.info("刷新令牌定时任务 authResponse: {}", JSON.toJSONString(authResponseMap));this.access_token = authResponseMap.get("access_token");this.refresh_token = authResponseMap.get("refresh_token");// 测试解析用户信息this.checkToken();}/*** 解析jwt中的用户信息*/private void checkToken() {if (StringUtils.isBlank(this.access_token)) {return;}MultiValueMap<String, String> map = new LinkedMultiValueMap<>();map.add("token", this.access_token);Map<String, String> authResponseMap = new RestTemplate().postForObject("http://127.0.0.1:10010/oauth/check_token", map, Map.class);log.info("解析jwt中的用户信息 authResponse: {}", JSON.toJSONString(authResponseMap));}}

4、测试

访问 http://127.0.0.1:10020/index.html 进行授权

这里贴出相关数据

普通token存储认证返回

{"access_token": "b220ad2b-0907-47a7-b7a3-036f15f06834","token_type": "bearer","refresh_token": "7a1aefaa-8070-4bb4-8b15-e829a2584b12","expires_in": 3775,"scope": "all"
}

token使用jwt存储认证返回

{"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE2NDg4NzEyODAsImF1dGhvcml0aWVzIjpbIlJPTEVfYWRtaW4iXSwianRpIjoiZDI2YzAxZGItY2E4ZC00ODBjLTk4MzAtMzdkODk0M2U4YWY5IiwiY2xpZW50X2lkIjoienFfYXBwX2lkIn0.tzjoVFzsPjRPUPnsL3xaFVGENEBg2_V7bDEVk7EbfA0","token_type": "bearer","refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicmVzMSJdLCJ1c2VyX25hbWUiOiJhZG1pbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiJkMjZjMDFkYi1jYThkLTQ4MGMtOTgzMC0zN2Q4OTQzZThhZjkiLCJleHAiOjE2NDkxMjY4MTIsImF1dGhvcml0aWVzIjpbIlJPTEVfYWRtaW4iXSwianRpIjoiNmFjZDQwYmYtYjk4Yi00Y2RkLWI4MDQtMTBlMzM1ZDNjY2YzIiwiY2xpZW50X2lkIjoienFfYXBwX2lkIn0.gnrtIKXhE71pJ1Fn5HmTZU-_3GW-Wst8lNrMplveipw","expires_in": 3599,"scope": "all","jti": "d26c01db-ca8d-480c-9830-37d8943e8af9","author": "zhengqingya"
}

解析jwt中的用户信息,即上面的access_token

原生JWT返回信息

{"aud": ["res1"],"user_name": "admin","scope": ["all"],"active": true,"exp": 1648871280,"authorities": ["ROLE_admin"],"jti": "d26c01db-ca8d-480c-9830-37d8943e8af9","client_id": "zq_app_id"
}

自定义JWT返回信息

{"aud": ["res1"],"user_name": "admin","scope": ["all"],"active": true,"exp": 1648890210,"authorities": ["ROLE_admin"],"jti": "d26c01db-ca8d-480c-9830-37d8943e8af9","client_id": "zq_app_id","info": {"author": "zhengqingya","gitee": "https://gitee.com/zhengqingya","user": {"username": "zq_app_id","authorities": [],"accountNonExpired": true,"accountNonLocked": true,"credentialsNonExpired": true,"enabled": true}}
}

七、本文案例demo源码

https://gitee.com/zhengqingya/java-workspace


今日分享语句:
你勤奋充电努力工作保持身材,对人微笑这些都不是为了取悦他人,而是为了扮靓自己照亮自己的心,告诉自己我是一股独立向上的力量。

Spring Security(5) 整合OAuth2相关推荐

  1. spring security oauth2_SpringBoot2 整合OAuth2实现统一认证

    关于OAuth2不做介绍了,网络太多了. 环境:2.2.11.RELEASE + OAuth2 + Redis redis用来实现token的存储. pom.xml org.springframewo ...

  2. 实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式统一认证授权!

    今天这篇文章介绍一下Spring Cloud Gateway整合OAuth2.0实现认证授权,涉及到的知识点有点多,有不清楚的可以看下陈某的往期文章. 文章目录如下: 微服务认证方案 微服务认证方案目 ...

  3. Spring Security 4 整合Hibernate 实现持久化登录验证(带源码)

    上一篇文章:Spring Security 4 整合Hibernate Bcrypt密码加密(带源码) 原文地址:http://websystique.com/spring-security/spri ...

  4. Spring Security(二):OAuth2协议

    ​ Spring Security(二):OAuth2.0协议 活动地址:CSDN21天学习挑战赛 今天学习与研究了OAuth2.0协议,记录一下,方便后面查阅 OAuth2.0即是一个开放标准,我们 ...

  5. Spring Security——简单第三方OAuth2登录自动配置——GitHub登录DEMO

    GitHub OAuth2 APP申请 https://github.com/settings/applications/new Maven <!--Spring Security-->& ...

  6. Spring Boot+Vue/前后端分离/高并发/秒杀实战课程之spring Security快速搭建oauth2 内存版身份认证

    Springboot快速搭建oauth2 内存版身份认证 环境准备 点击[Create New Project]创建一个新的项目 项目环境配置 配置Thymeleaf 搭建oauth2认证,加入两个依 ...

  7. (附源码)Spring Boot 框架整合 OAuth2 实现单点登录 SSO 详细完整源码教程!

    1.  前言 技术这东西吧,看别人写的好像很简单似的,到自己去写的时候就各种问题,"一看就会,一做就错".网上关于实现SSO的文章一大堆,但是当你真的照着写的时候就会发现根本不是那 ...

  8. Spring Security 5.x+OAuth2.0+OIDC1.0

    Spring Security+OAuth2.0+OIDC1.0 文章目录 Spring Security+OAuth2.0+OIDC1.0 前言 一.准备工作 1.Spring Security相关 ...

  9. (二)spring security:使用 OAuth2 SSO 实现单点登录

    一.前言 也许,我应该延续上一篇"(一)spring security:能做什么?"接着写,比如:如何实现RBAC权限动态控制.后端"验证码"生成与校验.JWT ...

最新文章

  1. npoi的mvc怎么ajax导出,asp.net mvc利用NPOI导入导出Excel解决方法
  2. MS SQL入门基础:删除数据
  3. python的序列化是什么意思_python什么是反序列化?
  4. C++new和delete运算符
  5. MVP:界面与业务逻辑分离在Winform中的应用
  6. 机器学习实际应用_机器学习的实际好处是什么?
  7. 教育部认可公众号博主是自由职业,网友:公号被封算失业吗?
  8. Android5.0以下 源码分析Notification的notify
  9. 不被大神Hinton认同,否定现有同行成果,谷歌这篇烧脑研究最终拿下ICML2019最佳论文...
  10. Setup Factory 9安装前卸载旧版本的方法
  11. 六石编程学:功能要定期测试
  12. 实验一:端口扫描(X-scan)
  13. mysql 字符串拼接的几种方式
  14. 用百用计算机弹出,CPU使用率老是100%怎么办?小编详解解决CPU过高的问题
  15. STM32F412 串口接收不到数据的问题
  16. wamp中php无法启动,wamp无法正常启动
  17. 京杭大运河北线疏浚穿越黄河地形UTM平面直角坐标系分析GIS模型建立
  18. WSA(win11子系统)安卓应用抢先体验
  19. 数字图像处理之特征提取及常用方法
  20. OS=Windows and the assembly descriptor contains a *nix-specific root-relative-reference 错误

热门文章

  1. 与servere.exe的战斗历程
  2. 商业人像精修皮肤质感增加PS插件_安装说明
  3. 网页宽度打印出A4纸
  4. 26.菊花厂员工泄密事件(Qt5文件及磁盘处理)--- OpenCV从零开始到图像(人脸 + 物体)识别系列
  5. Java多态的概念、优点和用法
  6. 【MATLAB教程案例43~50总结】MATLAB三维重建类算法仿真经验和技巧总结
  7. LeetCode.天际线问题
  8. Perl——正则表达式之贪婪模式和非贪婪模式
  9. MISC_MSISDN 获取手机号
  10. Xen server三为xen添加存储及创建虚拟机