18.Oauth2-微服务认证

这篇具有很好参考价值的文章主要介绍了18.Oauth2-微服务认证。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

18.Oauth2-微服务认证,skill,微服务,面试,架构

18.Oauth2-微服务认证,skill,微服务,面试,架构

1.Oauth2

OAuth 2.0授权框架支持第三方支持访问有限的HTTP服务,通过在资源所有者和HTTP服务之间进行一个批准交互来代表资源者去访问这些资源,或者通过允许第三方应用程序以自己的名义获取访问权限。

18.Oauth2-微服务认证,skill,微服务,面试,架构

为了方便理解,可以想象OAuth2.0就是在用户资源和第三方应用之间的一个中间层,它把资源和第三方应用隔开,使得第三方应用无法直接访问资源,从而起到保护资源的作用。

为了访问这种受保护的资源,第三方应用(客户端)在访问的时候需要提供凭证。即,需要告诉OAuth2.0你是谁你要做什么。

用户可以将用户名和密码告诉第三方应用,让第三方应用直接以你的名义去访问,也可以授权第三方应用去访问。

例如,微信公众平台开发,在微信公众平台开发过程中当我们访问某个页面,页面可能弹出一个提示框应用需要获取我们的个人信息问是否允许,点确认其实就是授权第三方应用获取我们在微信公众平台的个人信息,这里微信网页授权就是使用的OAuth2.0。

  • 第三方应用程序(Third-party application): 又称之为客户端(client),我们自己开发的各种客户端,对我们自己的项目来说,QQ、微信、支付宝等是第三方应用程序。

  • HTTP 服务提供商(HTTP service): 我们开发的项目以及 QQ、微信、支付宝、钉钉等都可以称之为“服务提供商”。

  • 资源所有者(Resource Owner): 又称之为用户(user),拥有账号密码的人。

  • 用户代理(User Agent): 用来访问资源,比如浏览器,代替用户去访问这些资源。

  • 认证服务器(Authorization server): 即服务提供商专门用来处理认证的服务器,主要就是实现登录、授权功能。

  • 资源服务器(Resource server): 即服务提供商存放用户生成的资源的服务器,比如电商中的商品模块、订单模块等,是用来处理具体业务的服务器。

        OAuth2.0协议流程描述了四种角色之间的交互过程,如下图所示。

18.Oauth2-微服务认证,skill,微服务,面试,架构

        简单说,OAuth 就是一种授权机制。数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据。系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使用。

令牌(token)与密码(password)的作用是一样的,都可以进入系统,但是有三点差异。

  • 令牌是短期的,到期会自动失效,用户自己无法修改。密码一般长期有效,用户不修改,就不会发生变化。

  • 令牌可以被数据所有者撤销,会立即失效。

  • 令牌有权限范围(scope),对于网络服务来说,只读令牌就比读写令牌更安全。密码一般是完整权限。

上面这些设计,保证了令牌既可以让第三方应用获得权限,同时又随时可控,不会危及系统安全。这就是 OAuth 2.0 的优点。

注意,只要知道了令牌,就能进入系统。系统一般不会再次确认身份,所以令牌必须保密,泄漏令牌与泄漏密码的后果是一样的。 这也是为什么令牌的有效期,一般都设置得很短的原因。

1.1 开放平台

        开放平台(Open Platform)在软件行业和网络中,开放平台是指软件系统通过公开其应用程序编程接口(API)或函数(function)来使外部的程序可以增加该软件系统的功能或使用该软件系统的资源,而不需要更改该软件系统的源代码。

        在互联网时代,把网站的服务封装成一系列计算机易识别的数据接口开放出去,供第三方开发者使用,这种行为就叫做Open API,提供开放API的平台本身就被称为开放平台。

        第一种是技术性的开放,例如百度、腾讯、阿里巴巴等,例如阿里可以提供标准化的应用软件,但是数百万形形色色的卖家对于个性化要求的软件,并不是一个公司的力量可以满足的,所以就把这些需求开放给众多的第三方开发者的方式。再例如google的基于Linux平台的开源手机操作系统就被认为会很快打败Nokia塞班系统。这一种技术性开放平台虽然目前来看跟B2C企业的开放平台关系不大,但是也能从一定程度上说明开放平台是互联网企业的趋势。

        第二种开放平台是指软件系统通过公开其应用程序编程接口(API)或函数(function)来使外部的程序可以增加该软件系统的功能或使用该软件系统的资源,而不需要更改该软件系统的源代码。B2C企业开放平台又包含两种形式,A:淘宝商城、日本乐天这种纯平台的模式,即自己不碰商品的进销存,全部由入驻商家来做;B:美国亚马逊、当当网、京东商城这种“自营+联营”的模式。

1.2 开放平台交互模型

三个角色:

  • 资源拥有者:用户

  • 客户端:各种app、浏览器

  • 服务提供方:包含两个角色

    认证服务器

    资源服务器

1.2.1 认证服务器

认证服务器负责对用户进行认证,并授权给客户端权限。一般的认证都是通过对账号密码进行验证实现,而难点在于怎么进行授权。比如我们使用第三方登录 "哔哩哔哩",可以看到如使用 QQ 登录的授权页面上有 "哔哩哔哩将获取以下权限" 的字样以及权限信息

18.Oauth2-微服务认证,skill,微服务,面试,架构

认证服务器需要知道请求授权的客户端的身份以及该客户端请求的权限。常见的做法是为每一个客户端预先分配一个 id,并给每个 id 对应一个名称以及权限信息。这些信息可以写在认证服务器上的配置文件里,今后客户端每次打开授权页面的时候,客户端需要将该id发送到认证服务器,0Auth2.0就可以用来自动给客户端分配id,同时完成配置文件的自动更新。

1.3 OAuth2 开放平台

开放平台是由 OAuth2.0 协议发展而来的一个产品,它的作用是让客户端自己去这上面进行注册、申请,通过之后系统自动分配 客户端id ,并完成配置的自动更新。

客户端要完成申请,通常需要申请人填写客户端程序的类型(Web、App、微信小程序、支付宝小程序等等)、企业信息、营业执照、法人信息以及想要获取权限等信息,申请需要得到得到服务提供上的审核通过之后,开发平台才会自动分配一个客户端id给客户端。

在通过审核之后,第三方应用在进行认证时,就会想需要获取到的权限信息展示到页面上,例如哔哩哔哩获取QQ权限。授权成功之后认证服务器需要把产生的 access_token 发送给客户端,客户端才能访问具体的资源(头像、性别之类的),大致过程如下:

  • 让客户端在开放平台提交申请时候,填写一个 网址,例如:www.baidu.com,此网址主要用来获取认证码。

  • 当有用户授权成功之后,认证服务器将页面重定向到这个网址,并将生成的 access_token拼接到该网址后面,例如:www.baidu.com?access_token=123 

  • 客户端接收到access_token,之后客户端就可以拿着这个token去获取需要的数据了

1.3.1 令牌

传统项目向服务端请求数据,服务端需要频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,这样效率非常低下,怎么提高效率呢?Token便应运而生。

Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。

1.3.2 Access Token

Access Token 是客户端访问资源服务器的令牌。拥有这个令牌代表着得到用户的授权,即具备了访问资源的权限。同时这个授权应该是临时的,只能在一定期限内使用。主要原因是因为Access Token 在使用的过程中很有可能会泄露,被不法分子利用获取我们的数据。所以Access Token应该只能在某个期限内使用,这样可以降低因 Access Token 泄露而带来的风险。

1.4 认证模式

OAuth2.0中定义了四种授权模式:

  • authorization code 授权码模式

  • implicit 简化模式

  • resource owner password credentials 密码模式

  • client credentials 客户端模式

常见模式:授权码、密码模式

1.4.1 授权码模式

授权码模式(authorization code)是功能最完整、流程最严密的授权模式,code保证了token的安全性,即使code被拦截,由于没有secret,也是无法通过code获得token的。

角色行为与功能
  • 资源所有者

    只需要允许或拒绝第三方应用获得授权

  • 第三方应用

    申请成为资源服务器的第三方应用

    获取资源服务器提供的资源

  • 授权服务器

    提供授权许可code、令牌token等

  • 资源服务器

    提供给第三方应用开放资源的接口

18.Oauth2-微服务认证,skill,微服务,面试,架构

时序图

18.Oauth2-微服务认证,skill,微服务,面试,架构

环境搭建

创建父项目

18.Oauth2-微服务认证,skill,微服务,面试,架构

18.Oauth2-微服务认证,skill,微服务,面试,架构

指定打包方式为pom

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.woniuxy</groupId>
    <artifactId>oauth2</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>
</project>

创建auth-server认证服务器模块

18.Oauth2-微服务认证,skill,微服务,面试,架构

18.Oauth2-微服务认证,skill,微服务,面试,架构

导入依赖

18.Oauth2-微服务认证,skill,微服务,面试,架构

导入依赖版本如下

<properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    <spring-cloud-alibaba.version>2.2.2.RELEASE</spring-cloud-alibaba.version>
</properties>

oauth2依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
    <version>2.2.4.RELEASE</version>
</dependency>

创建用户信息配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{
	
	//密码编码器
	@Bean
	public BCryptPasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
	
    // 基于内存的用户信息
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth
			.inMemoryAuthentication()	//内存认证
			.withUser("zhangsan")		//用户名
			.password(passwordEncoder().encode("123"))	//密码
			.authorities("ROLE_ADMIN");	//角色
	}
}

创建客户端配置类,配置客户端信息

import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;

import javax.annotation.Resource;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter{
	
	@Resource
	private BCryptPasswordEncoder passwordEncoder;
	
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		//配置客户端
		clients
			.inMemory()		//内存方式
			.withClient("client")	//客户端名字
			.secret(passwordEncoder.encode("secret"))	//客户端秘钥
			.authorizedGrantTypes("authorization_code")//授权类型
			.scopes("all")	//授权范围
			.redirectUris("http://www.baidu.com");	//回调网址,携带授权码
	}
}

在application.yml文件中配置以下信息

server:
  port: 8000
spring:
  application:
    name: oauth

启动项目进行登录

localhost:8000/login

进入登录页面,输入账号:zhangsan,密码:123进行登录

18.Oauth2-微服务认证,skill,微服务,面试,架构

登录成功之后向服务器发送请求获取授权码,在地址栏上输入以下内容回车

http://localhost:8080/oauth/authorize?client_id=client&response_type=code

可以看到一个授权页面,询问用户是否进行授权

18.Oauth2-微服务认证,skill,微服务,面试,架构

授权成功之后会重定向到AuthorizationServerConfiguration配置类中指定的地址,并以参数的方式携带授权码

通过postman发送请求向服务器获取token

地址栏填写:http://client:secret@localhost:8000/oauth/token

填写客户端账号密码

18.Oauth2-微服务认证,skill,微服务,面试,架构

填写授权类型、授权码,发送请求

18.Oauth2-微服务认证,skill,微服务,面试,架构

成功之后在postman上可以看到以下信息

18.Oauth2-微服务认证,skill,微服务,面试,架构

表示成功

注意:每个授权码只能使用一次

1.4.2 密码模式

密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向"服务商提供商"索要授权。

在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

修改AuthorizationServerConfiguration配置类,添加密码模式

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    //配置客户端
    clients
        .inMemory()		
        .withClient("client")
        .secret(passwordEncoder.encode("secret"))
        .authorizedGrantTypes("authorization_code","password") //添加密码授权模式
        .scopes("all")	//授权范围
        .redirectUris("http://www.woniuxy.com");
}

在postman中新开一个请求,地址栏中填写:http://localhost:8080/oauth/token

密码授权模式要求以请求头的方式提交客户端账号密码,并且需要对账号密码进行base64加密,因此选择Authorization选项卡,设置TYPE为"Basic Auth",并填写客户端账号密码

18.Oauth2-微服务认证,skill,微服务,面试,架构

在请求体中设置授权类型、用户账号密码参数

18.Oauth2-微服务认证,skill,微服务,面试,架构

发送请求测试

18.Oauth2-微服务认证,skill,微服务,面试,架构

可以发现此时并不支持密码模式,即使在AuthorizationServerConfiguration配置类中指定了密码模式。

原因是此时代码中缺少对密码模式的支持,在oauth2中需要添加AuthenticationManager对象对密码模式进行支持。

在WebSecurityConfiguration配置类中配置 AuthenticationManager

// 配置 AuthenticationManager(密码模式需要该对象进行账号密码校验)
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

在AuthorizationServerConfiguration类中注入AuthenticationManager,并重写以下方法

// 认证管理器
@Autowired
private AuthenticationManager authenticationManager;

//配置使用的 AuthenticationManager 实现用户认证的功能
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.authenticationManager(authenticationManager);
}

重启项目再次发送请求获取token

18.Oauth2-微服务认证,skill,微服务,面试,架构

整合JWT

导入了oauth2依赖就自动导入的JWT相关依赖,因此不用单独导入JWT,只需要进行设置就行

创建TokenConfiguration配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

@Configuration
public class TokenConfiguration {
    // 密码
    private static String SIGNING_KEY="www.woniuxy.com";

    // token转换器
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter jwtAccessTokenConverter = 
            new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigningKey(SIGNING_KEY);
        return jwtAccessTokenConverter;
    }

    // 令牌存储策略:jwt方式
    @Bean
    public TokenStore tokenStore(){
        return new JwtTokenStore(accessTokenConverter());
    }
}

在AuthorizationServerConfiguration配置类中注入相关对象

@Resource
private TokenStore tokenStore;

@Resource
private JwtAccessTokenConverter jwtAccessTokenConverter;

@Resource
private ClientDetailsService clientDetailsService;

在AuthorizationServerConfiguration配置类中编写token服务方法,该方法主要用来设置

private AuthorizationServerTokenServices tokenServices(){
    // 创建服务对象
    DefaultTokenServices services = new DefaultTokenServices();
    // 设置客户端详情服务
    services.setClientDetailsService(clientDetailsService);
    // 支持刷新令牌
    services.setSupportRefreshToken(true);
    // 不重复使用refreshtoken,每次刷新之后只能用新的refreshtoken才能继续刷新
	services.setReuseRefreshToken(false);
    // 设置令牌存储策略
    services.setTokenStore(tokenStore);

    // 设置令牌增强
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));
    services.setTokenEnhancer(tokenEnhancerChain);

    // 设置令牌过期时间
    services.setAccessTokenValiditySeconds(600);
    services.setRefreshTokenValiditySeconds(6000);

    return services;
}

修改configure(AuthorizationServerEndpointsConfigurer endpoints)方法,添加token服务

//配置使用的 AuthenticationManager 实现用户认证的功能
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints
        .authenticationManager(authenticationManager) // 认证管理器
        .tokenServices(tokenServices());	// 配置token服务
}

重启项目发送请求获取token

18.Oauth2-微服务认证,skill,微服务,面试,架构

如果想要获取到refreshtoken,可以修改AuthorizationServerConfiguration配置类,添加refresh_token授权方式

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    //配置客户端
    clients
        .inMemory()		
        .withClient("client")
        .secret(passwordEncoder.encode("secret"))	
        .authorizedGrantTypes("authorization_code","password","refresh_token") 
        .scopes("all")
        .redirectUris("http://www.woniuxy.com");
}

重启项目测试

18.Oauth2-微服务认证,skill,微服务,面试,架构

18.Oauth2-微服务认证,skill,微服务,面试,架构

整合数据库(user)

建表SQL

create database sc default character set=utf8;

DROP TABLE IF EXISTS `perms`;
CREATE TABLE `perms` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `perms` VALUES (3001,'user:add'),(3002,'user:del'),(3003,'user:find'),(3004,'user:update'),(3005,'goods:add'),(3006,'goods:find'),(3007,'goods:del'),(3008,'goods:update');

DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `role` VALUES (2001,'ROLE_ADMIN'),(2002,'ROLE_USER');


DROP TABLE IF EXISTS `role_perms`;
CREATE TABLE `role_perms` (
  `rid` int(11) DEFAULT NULL,
  `pid` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `role_perms` VALUES (2001,3001),(2001,3003),(2001,3004),(2002,3005),(2002,3006),(2002,3007),(2002,3008);

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) DEFAULT NULL,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(64) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES (1001,'zhangsan','$2a$10$pINVnd8.cXScFXCxI2x4cem4fOexA2J5TNY/Mx2CjN6mJuYGBNG0m'),(1002,'wangwu','wangwu');

DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
  `uid` int(11) DEFAULT NULL,
  `rid` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `user_role` VALUES (1001,2001),(1002,2002),(1003,2002);

auth-server的pom.xml中引入mybatis

<!--mybatis-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.4</version>
</dependency>

在application.yml中配置mybatis参数

mybatis:
  type-aliases-package: com.woniuxy.authserver.entity
  mapper-locations: classpath:/mapper/*.xml

创建Perms、Role、User实体类,注意:实体类必须实现序列化接口,不然运行过程中可能会报Failed to find access token for token错误

import lombok.Data;

@Data
public class Perms implements Serializable {
    private static final long serialVersionUID = 1L;
    private int id;
    private String name;
}
import lombok.Data;
import java.util.List;

@Data
public class Role implements Serializable {
    private static final long serialVersionUID = 1L;
    private int id;
    private String name;
    private List<Perms> perms;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Slf4j
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements UserDetails, Serializable {

    private static final long serialVersionUID = 1L;

    private int id;
    private String username;
    private String password;
    private List<Role> roles;

    // 返回当前用户的所有角色、权限信息
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        log.debug("获取用户角色权限信息");
        // 新建集合
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        // 遍历role
        for(Role role : this.roles){
            // 放入角色信息
            grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
            // 遍历当前角色的所有权限信息
            for(Perms perms : role.getPerms()){
                grantedAuthorities.add(new SimpleGrantedAuthority(perms.getName()));
            }
        }
        log.debug(grantedAuthorities.toString());
        return grantedAuthorities;
    }

    // 获取用户名
    @Override
    public String getUsername() {
        return this.username;
    }

    // 账号是否过期    true表示未过期   false表示过期
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    // 账号是否被锁定  true表示未锁定   false表示锁定
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    // 凭证是否过期  true表示未过期   false表示过期
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    // 用户是否被禁用  true表示未禁用   false表示禁用
    @Override
    public boolean isEnabled() {
        return true;
    }
}

创建UerMapper接口

import com.woniuxy.springsecurity.entity.User;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper {
    public User findByName(String username);
}

在resources目录下创建mapper文件夹,并在该文件夹下创建Mapper文件

18.Oauth2-微服务认证,skill,微服务,面试,架构

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.woniuxy.authserver.mapper.UserMapper" >
    <select id="findByName" resultMap="user_map">
        select * from user where username = #{username}
    </select>

    <resultMap id="user_map" type="User">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>

        <collection property="roles" ofType="Role" column="id" select="findRolesByUid"></collection>
    </resultMap>

    <select id="findRolesByUid" resultMap="role_map">
        select r.id,r.name from user_role ur,role r where ur.rid = r.id and ur.uid = #{id}
    </select>
    <resultMap id="role_map" type="Role">
        <id column="id" property="id"></id>
        <result column="name" property="name"></result>

        <collection property="perms" ofType="Perms" column="id" select="findPermsByRid"></collection>
    </resultMap>

    <select id="findPermsByRid" resultType="Perms">
        select p.id,p.name from role_perms rp,perms p where rp.pid = p.id and rp.rid = #{rid}
    </select>
</mapper>

创建CustomUserDetailsServiceImpl类实现UserDetailsService接口

import com.woniuxy.authserver.entity.User;
import com.woniuxy.authserver.mapper.UserMapper;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class CustomUserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.查询用户
        User user = userMapper.findByName(username);

        //2.判断
        if (user == null) throw new UsernameNotFoundException("用户不存在");

        //3.返回用户信息
        return user;
    }
}

在配置类WebSecurityConfiguration中注入UserDetailsService对象,并修改configure(AuthenticationManagerBuilder auth)反方指定用户信息从数据库中获取

@Resource
private UserDetailsService userDetailsService;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    //auth
        //.inMemoryAuthentication()	//内存认证
        //.withUser("zhangsan")		//用户名
        //.password(passwordEncoder().encode("123"))	//密码
        //.authorities("ROLE_ADMIN");	//角色
    auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

重启auth-server服务,进行认证

封装用户id

在生成token时可以将用户id封装到token中,以便后期使用

修改TokenConfiguration类中的accessTokenConverter()方法,在创建转换器时重写enhance方法

// token转换器
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter jwtAccessTokenConverter = 
        new JwtAccessTokenConverter(){
        @Override
        public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
            final Map<String,Object> map = new HashMap<>();
            // 从认证对象中得到用户信息
            User user = (User) authentication.getUserAuthentication().getPrincipal();
            // 将用户id放到token中
            map.put("uid", user.getId());
            ((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(map);
            // 返回
            return super.enhance(accessToken, authentication);
        }
    };
    jwtAccessTokenConverter.setSigningKey(SIGNING_KEY);
    return jwtAccessTokenConverter;
}

利用postman进行测试

18.Oauth2-微服务认证,skill,微服务,面试,架构

返回的结果中可以看到用户id,token中也包含了用户id

检验token是否过期

在org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint类中定义了校验token的接口/oauth/check_token,该接口可以用来校验token是否合法、是否过期、是否是伪造的

@RequestMapping(value = "/oauth/check_token")
@ResponseBody
public Map<String, ?> checkToken(@RequestParam("token") String value) {

    OAuth2AccessToken token = resourceServerTokenServices.readAccessToken(value);
    if (token == null) {
        throw new InvalidTokenException("Token was not recognised");
    }

    if (token.isExpired()) {
        throw new InvalidTokenException("Token has expired");
    }

    OAuth2Authentication authentication = resourceServerTokenServices.loadAuthentication(token.getValue());

    Map<String, Object> response = (Map<String, Object>)accessTokenConverter.convertAccessToken(token, authentication);

    // gh-1070
    response.put("active", true);	// Always true if token exists and not expired

    return response;
}

只是该接口oauth2默认情况下是不对外公开的,如果要使用该接口那就必须手动配置开启,在AuthorizationServerConfiguration配置类中重写以下方法

//设置 /oauth/check_token 端点,通过认证后可访问。
//该端点对应 CheckTokenEndpoint类,用于校验访问令牌的有效性。
//在客户端访问资源服务器时,会在请求中带上访问令牌。
//在资源服务器收到客户端的请求时,会使用请求中的访问令牌,找授权服务器确认该访问令牌的有效性。
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    // 默认是denyAll():拒绝所有
    oauthServer.checkTokenAccess("permitAll()");
}

checkTokenAccess常用值有三种:

  • denyAll():拒绝所有请求,不开放该接口

  • isAuthenticated():只对完成认证之后的请求开放

  • permitAll():对所有请求开放

测试:登录成功之后在Postman中发送请求进行测试

接口url:http://localhost:8080/oauth/check_token

18.Oauth2-微服务认证,skill,微服务,面试,架构

返回的结果中包含了用户的用户名、权限等信息,还包括了token是否可用的信息

如果返回以下信息表示token已经过期

18.Oauth2-微服务认证,skill,微服务,面试,架构

而如果返回以下信息表示token非法

18.Oauth2-微服务认证,skill,微服务,面试,架构

通过refresh_token获取新token

获取token和刷新token使用的是同一个接口,所以地址栏url还是

http://local:8080/oauth/token

只是grant_type需要换成refresh_token,然后将之前的refresh token作为参数传递给后台

18.Oauth2-微服务认证,skill,微服务,面试,架构

还是需要将客户端id、密码以base64编码放到请求头中

18.Oauth2-微服务认证,skill,微服务,面试,架构

发送请求得到结果

18.Oauth2-微服务认证,skill,微服务,面试,架构

根据结果可以知道,token和refresh_token都会自动刷新,这样做的好处是当token过期时通过程序调用刷新接口,获取到新的token和refresh_token,实现自动续期。

refresh_token如果过期会得到以下结果

18.Oauth2-微服务认证,skill,微服务,面试,架构

refresh_token过期就需要重新登录

1.5 资源服务器

创建resource子模块,导入相关依赖

18.Oauth2-微服务认证,skill,微服务,面试,架构

设置父子关系

创建OAuth2ResourceServerConfig配置类

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;

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
 
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            // 设置请求,需要认证后访问
            .anyRequest().authenticated();
    }
}

创建controller

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/resource")
public class ResourceController {

    @RequestMapping("/info")
    public String info(){

        return "success";
    }
}

配置application.yml

server:
  port: 8001
spring:
  application:
    name: resource
security:
  oauth2:
    # OAuth2 Client 配置,对应 OAuth2ClientProperties 类
    client:
      client-id: client
      client-secret: secret
    # OAuth2 Resource 配置,对应 ResourceServerProperties 类
    resource:
      token-info-uri: http://127.0.0.1:8000/oauth/check_token # 获得 Token 信息的 URL
    # 访问令牌获取 URL,自定义的
    access-token-uri: http://127.0.0.1:8000/oauth/token
management:
  endpoints:
    web:
      exposure:
        include: '*'

启动resource资源服务器

先进行认证,得到token和refresh_token

localhost:8000/oauth/token

18.Oauth2-微服务认证,skill,微服务,面试,架构

然后将得到的token放到请求资源服务器的请求头中

18.Oauth2-微服务认证,skill,微服务,面试,架构

发送请求后可以发现报500错误,查看resource控制台可以发现以下信息

org.springframework.web.client.HttpClientErrorException$Forbidden: 403 : [{"timestamp":"2022-05-07T03:40:14.063+00:00","status":403,"error":"Forbidden","message":"","path":"/oauth/check_token"}]

根据信息提示:没有权限访问 /oauth/check_token,该URL是认证服务器用来校验token是否合法的接口。资源服务器在接收到请求时会获取到token,然后调用认证服务器的/oauth/check_token接口去检验token,但是此时认证服务器还没有开放该端口(默认关闭),所以造成了403无法访问。

到认证服务器的AuthorizationServerConfiguration配置类中开启/oauth/check_token

//设置 /oauth/check_token 端点,通过认证后可访问。
//该端点对应 CheckTokenEndpoint类,用于校验访问令牌的有效性。
//在客户端访问资源服务器时,会在请求中带上访问令牌。
//在资源服务器收到客户端的请求时,会使用请求中的访问令牌,找授权服务器确认该访问令牌的有效性。
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    // 默认是denyAll():拒绝所有
    oauthServer.checkTokenAccess("isAuthenticated()");
}

重启认证服务器

重新进行认证得到token,然后用新的token再访问资源服务器

18.Oauth2-微服务认证,skill,微服务,面试,架构

看到success表明成功

角色权限管理

在资源服务器主启动类上添加@EnableGlobalMethodSecurity注解,开启spring security权限注解的支持

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ResourceApplication.class, args);
    }
}

在resource/info接口方法上添加注解@PreAuthorize并指定角色或权限

@RequestMapping("/info")
@PreAuthorize("hasRole('USER')")
public String info(){

    return "success";
}

利用postman再次访问该接口

18.Oauth2-微服务认证,skill,微服务,面试,架构

得到不允许访问的结果,表明角色权限管理生效

1.6 整合数据库(client)

建表SQL

CREATE TABLE `clientdetails` (
  `appId` VARCHAR(128) NOT NULL,
  `resourceIds` VARCHAR(256) DEFAULT NULL,
  `appSecret` VARCHAR(256) DEFAULT NULL,
  `scope` VARCHAR(256) DEFAULT NULL,
  `grantTypes` VARCHAR(256) DEFAULT NULL,
  `redirectUrl` VARCHAR(256) DEFAULT NULL,
  `authorities` VARCHAR(256) DEFAULT NULL,
  `access_token_validity` INT(11) DEFAULT NULL,
  `refresh_token_validity` INT(11) DEFAULT NULL,
  `additionalInformation` VARCHAR(4096) DEFAULT NULL,
  `autoApproveScopes` VARCHAR(256) DEFAULT NULL,
  PRIMARY KEY (`appId`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE `oauth_access_token` (
  `token_id` VARCHAR(256) DEFAULT NULL,
  `token` BLOB,
  `authentication_id` VARCHAR(128) NOT NULL,
  `user_name` VARCHAR(256) DEFAULT NULL,
  `client_id` VARCHAR(256) DEFAULT NULL,
  `authentication` BLOB,
  `refresh_token` VARCHAR(256) DEFAULT NULL,
  PRIMARY KEY (`authentication_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE `oauth_approvals` (
  `userId` VARCHAR(256) DEFAULT NULL,
  `clientId` VARCHAR(256) DEFAULT NULL,
  `scope` VARCHAR(256) 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(256) DEFAULT NULL,
  `client_secret` VARCHAR(256) DEFAULT NULL,
  `scope` VARCHAR(256) DEFAULT NULL,
  `authorized_grant_types` VARCHAR(256) DEFAULT NULL,
  `web_server_redirect_uri` VARCHAR(256) DEFAULT NULL,
  `authorities` VARCHAR(256) DEFAULT NULL,
  `access_token_validity` INT(11) DEFAULT NULL,
  `refresh_token_validity` INT(11) DEFAULT NULL,
  `additional_information` VARCHAR(4096) DEFAULT NULL,
  `autoapprove` VARCHAR(256) DEFAULT NULL,
  PRIMARY KEY (`client_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE `oauth_client_token` (
  `token_id` VARCHAR(256) DEFAULT NULL,
  `token` BLOB,
  `authentication_id` VARCHAR(128) NOT NULL,
  `user_name` VARCHAR(256) DEFAULT NULL,
  `client_id` VARCHAR(256) DEFAULT NULL,
  PRIMARY KEY (`authentication_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE `oauth_code` (
  `code` VARCHAR(256) DEFAULT NULL,
  `authentication` BLOB
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE `oauth_refresh_token` (
  `token_id` VARCHAR(256) DEFAULT NULL,
  `token` BLOB,
  `authentication` BLOB
) ENGINE=INNODB DEFAULT CHARSET=utf8;

在表 oauth_client_details 中增加一条客户端配置记录,在填入时可以按照AuthorizationServerConfiguration配置类中的客户端配置进行配置

配置的效果如下:

18.Oauth2-微服务认证,skill,微服务,面试,架构

注:各字段解释说明

  • client_id:客户端标识

  • client_secret:客户端安全码。注意安全码不能是明文需要加密,此处可以写一段程序,然后使用BCryptPasswordEncoder为客户端安全码加密,得到加密之后的安全码,再写入到数据库中,例如:

  • System.out.println(new BCryptPasswordEncoder().encode("secret"));

  • scope:客户端授权范围

  • authorized_grant_types:客户端授权类型,支持多种类型,多种类型之间用逗号隔开

  • web_server_redirect_uri:服务器回调地址

创建实体类User、Role、Perms

在auth-server模块的pom.xml中引入mybatis相关依赖

<!-- spring-boot-starter-jdbc 内置了HikariCP 连接池,所以使用该连接池连接数据库 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 获取application.yml文件中的配置 -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<optional>true</optional>
</dependency>

application.yml文件中添加数据库相关配置

server:
  port: 8000
spring:
  application:
    name: oauth
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbc-url: jdbc:mysql://localhost:3306/sc?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
    username: root
    password: root
    hikari:
      minimum-idle: 5
      maximum-pool-size: 10
      auto-commit: true #自动提交
      pool-name: MYHIKARICP
      connection-test-query: SELECT 1 #测试是否能连接上数据库的SQL语句
  main:
    #true,后定义的bean会覆盖之前定义的相同名称的bean,生成dataSource替换掉原生的dataSource
    allow-bean-definition-overriding: true

创建数据库配置类DataSourceConfiguration,主要配置用到的数据源,用HikariCP连接池的数据源替换到spring内置的数据源。

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfiguration {
    @Bean   
    @Primary    
    //根据application.yml中的配置信息创建dataSource
    @ConfigurationProperties(prefix = "spring.datasource")
    //import javax.sql.DataSource;
    public DataSource dataSource() {
        //创建dataSource
        return DataSourceBuilder.create().build();
    }
}

在TokenConfiguration配置类中把token存储策略改成JDBC方式,将jwt存放到数据库中DataSource

@Resource
private DataSource dataSource;

// 令牌存储策略:jwt方式
@Bean
public TokenStore tokenStore(DataSource dataSource){
    //return new JwtTokenStore(accessTokenConverter());
    return new JdbcTokenStore(dataSource);
}

修改AuthorizationServerConfiguration配置类,添加ClientDetailsService clientDetailsService(DataSource dataSource)方法,让程序通过DataSource从数据库中获取到客户端信息

@Bean
public ClientDetailsService clientDetailsService(DataSource dataSource) {
    //在数据库中去获取客户端信息(oauth_client_details表)
    return new JdbcClientDetailsService(dataSource);
}

修改configure(ClientDetailsServiceConfigurer clients)方法指定到数据库获取客户端信息

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    //配置客户端
    //clients
    //.inMemory()		//内存方式
    //.withClient("client")	//客户端名字
    //.secret(passwordEncoder.encode("secret"))	//客户端秘钥
    //.authorizedGrantTypes("authorization_code","password","refresh_token")
    //.scopes("all")	//授权范围
    //.redirectUris("http://www.woniuxy.com");	//回调网址

    clients.withClientDetails(clientDetailsService);
}

完成之后重启项目,再次进行认证测试

正常情况下,测试完毕之后会在数据库的oauth_access_token 表中会增加一个记录,这个记录就是浏览器获取到的token和refresh token

18.Oauth2-微服务认证,skill,微服务,面试,架构

角色、权限管理测试

在resource服务的controller中添加以下方法

@RequestMapping("/message")
@PreAuthorize("hasRole('ADMIN')")
public String message(){

    return "message";
}

@RequestMapping("/data")
@PreAuthorize("hasAuthority('user:add')")
public String data(){

    return "data";
}
@RequestMapping("/test")
@PreAuthorize("hasAuthority('user:del')")
public String test(){

    return "test";
}

启动resource服务,通过postman分别测试info、message、data、test接口,如果只有message、data接口可以访问,那么说明角色、权限管理成功。文章来源地址https://www.toymoban.com/news/detail-687298.html

到了这里,关于18.Oauth2-微服务认证的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 微服务统一认证方案Spring Cloud OAuth2+JWT

    目录 前言 一、微服务架构下的统一认证场景 二、微服务架构下的统一认证思路 1.基于Session的认证方式 2.基于token的认证方式(主流) 三、OAuth2开放授权协议/标准 1.OAuth2介绍 2.OAuth2协议角色和流程 3.什么情况下需要使用OAuth2? 4.OAuth2的颁发Token授权方式 四、Spring Cloud OAuth2+JWT实现

    2023年04月09日
    浏览(71)
  • 认证服务---OAuth2.0基本介绍,微博登录整合到实际项目中【下篇】

    上一篇简单介绍了它的基本使用,这一篇就粗略说明一下如何在项目中实际应用 当你进行了授权之后,跳转到一个新的地址。这个地址应该是你访问接口的地址。在这个接口中完成相应的access_token获取,以及调用远程服务接口实现新用户注册 具体业务实现 1、选择登录方式,

    2023年04月12日
    浏览(33)
  • 34、商城系统(十五):认证服务,短信验证码,密码加盐,OAuth2.0社交登录,SpringSession认证功能,单点登录

    目录 一、新建认证服务 1.后端项目启动 2.前端页面复制 3.配置域名 4.配置gateway

    2024年02月19日
    浏览(49)
  • Spring Authorization Server入门 (八) Spring Boot引入Security OAuth2 Client对接认证服务

    在之前的文章中实现了一个认证服务,并且添加了一些自定义的内容,现在暂时没想到认证服务的新内容,本篇文章就先写一下客户端对接的吧,水一篇。 当用户通过客户端去访问一个受限的资源时,客户端会检测是否有登录信息,没有登录信息会重定向至认证服务器去请求

    2024年02月21日
    浏览(47)
  • OAuth2认证流程

    目录 什么是OAuth2 1. OAuth2认证流程 1、用户点击微信扫码 2、用户授权黑马网站访问用户信息 3、黑马程序员的网站获取到授权码 4、携带授权码请求微信认证服务器申请令牌 5、微信认证服务器向黑马程序员的网站响应令牌 6、黑马程序员网站请求微信资源服务器获取资源即用

    2024年02月16日
    浏览(54)
  • 如何支持微软邮箱OAuth2.0认证

    近期收到部分使用微软邮箱的客户反映,在EDI系统中无法连接到他们的企业邮箱中,连接过程中报错: IMAP protocol error. 1 NO LOGIN failed…,经确认是微软停用了邮箱的基本验证功能,客户端必须使用OAuth2.0认证,才可以进行连接。那么在知行EDI系统中该如何解决这一问题呢? 知

    2024年02月07日
    浏览(72)
  • Spring Oauth2.0 自定义认证模式

    在特定场景下,可能Oauth2自带的4种认证模式可能满足不了我们日常的使用,那么今天就为大家带来Oauth2自定义认证模式。 知道你们肯定没耐心读完(总结一句话就是授权用的),有耐心的可以读完下面的内容介绍: 首先呢在这之前我们要搞清楚什么是Oauth , OAuth 是一个开放标准,该

    2024年02月16日
    浏览(34)
  • 【Oauth2.0 单点登录 + 第三方授权认证】用户认证、授权模式

    本文主要对 SpringSecurity Oauth 2.0 用户认证,授权码授权模式、密码授权模式,以及授权流程进行讲解 开发中,有些功能只有管理员才有,普通用户是没有的。即需要对用户的身份进行认证,是管理员还是普通用户。认证方式有两种: 身份认证: 用户在访问相应资源时对用户

    2023年04月08日
    浏览(65)
  • SpringBoot 如何使用 OAuth2 进行认证和授权

    OAuth2 是一种授权框架,可以用于实现第三方应用程序访问用户资源的安全性。在 SpringBoot 中,我们可以使用 Spring Security 和 Spring OAuth2 来实现 OAuth2 的认证和授权功能。本文将介绍如何在 SpringBoot 中使用 OAuth2 进行认证和授权。 在开始介绍如何使用 OAuth2 进行认证和授权之前,

    2024年02月13日
    浏览(35)
  • Springdoc Swagger UI集成OAuth2认证

    之前的文章讲过OAuth2体系,以 授权码 流程为例(参见下图), 其中资源服务器(Resource Server)作为服务的提供者, 用户在客户端应用完成授权流程后,客户端应用需要 携带AccessToken请求资源服务器 , 也即是要想访问资源服务器就需要提供正确的 Authorization: Bearer AccessToke

    2024年02月02日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包