Spring Cloud【实现用户鉴权(什么是JWT、JWT原理、用户微服务、JWT工具类、用户服务实现JWT鉴权)】(八)

news2024/11/27 13:50:12

 

目录

Gateway解决如何允许跨域

服务网关Gateway实现用户鉴权_什么是JWT

服务网关Gateway实现用户鉴权_JWT原理

服务网关Gateway实现用户鉴权_用户微服务

服务网关Gateway实现用户鉴权_JWT工具类

服务网关Gateway实现用户鉴权_用户服务实现JWT鉴权


 

Gateway解决如何允许跨域

CORS

1、如何允许跨域,一种解决方法就是目的域告诉请求者允许什么来源域来请求,那么浏览器就会知道 B域是否允许A域发起请求。

2、CORS("跨域资源共享"(Cross-origin resource sharing))就是这样一种解决手段。 

CORS使得浏览器在向目的域发起请求之前先发起一个OPTIONS方式的请求到目的域获取目的域的信息,比如获取目的域允许什么域来请求的信息。 

spring:
 cloud:
   gateway:
     globalcors:
       cors-configurations:
         '[/**]':
           allowCredentials: true
           allowedOriginPatterns: "*"
           allowedMethods: "*"
           allowedHeaders: "*"
       add-to-simple-url-handler-mapping: true

实时效果反馈

1.当一个请求url的____之间任意一个与当前页面url不同即为跨域。

A 协议、域名

B 协议、端口

C 协议、域名、请求类型

D 协议、域名、端口

2.最常用解决跨域的手段是____。

A CORS

B COS

C COR

D 以上都是错误

服务网关Gateway实现用户鉴权_什么是JWT

什么是JWT 

JWT是一种用于双方之间传递安全信息的简洁的、URL安全的声明规范。定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。特别适用于分布式站点的单点登录 (SSO)场景。

传统的session认证 

每次提到无状态的 JWT时相信都会看到另一种基于Session 的用户认证方案介绍,这里也不例外,Session 的认证流程通常会像这样:

 

缺点:

安全性:CSRF攻击因为基于cookie来进行用户识别, cookie如果被截获,用户就会很容易受 到跨站请求伪造的攻击。

扩展性:对于分布式应用,需要实现 session 数据共享

性能:每一个用户经过后端应用认证之后,后端应用都要在服务端做一次记录,以方便用户 下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开 销会明显增大,与REST风格不匹配。因为它在一个无状态协议里注入了状态。 

JWT方式 

优点:

1、无状态

2、适合移动端应用

3、单点登录友好 

实时效果反馈

1.传统的session认证缺点的是__。

A 内存容量

B 网络安全

C 分布式应用session共享

D 以上都正确

2.下列属于JWT优点的是__。

A 无状态

B 适合移动端应用 

C 单点登录友好

D 以上都正确

服务网关Gateway实现用户鉴权_JWT原理

 JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

{
  "姓名": "张三",
  "角色": "管理员",
  "到期时间": "2030年7月1日0点0分"
}

 注意:

用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候会加上签名,服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

JWT的结构 

注意: 它是一个很长的字符串,中间用点( . )分隔成三个部分。注 意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。 

JWT 的三个部分依次如下: 

头部(header)

载荷(payload)

签证(signature) 

Header 

JSON对象,描述 JWT 的元数据。其中 alg 属性表示签名的算法 (algorithm),默认是 HMAC SHA256(写成 HS256);typ 属性 表示这个令牌(token)的类型(type),统一写为 JWT。

{
  "alg": "HS256",
  "typ": "JWT"
}

 注意: 上面代码中, alg 属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256); typ 属性表示这个令牌 (token)的类型(type),JWT 令牌统一写为 JWT 然后将头部进行Base64编码构成了第一部分,Base64是一种用64个字符来表示任意二进制数据的方法,Base64是一种任意二进制到文本字符串的编码方法,常用于在URL、Cookie、网页中传输少量二进制数据。

Payload 

内容又可以分为3中标准

1、标准中注册的声明

2、公共的声明

3、私有的声明 

payload-标准中注册的声明 (建议但不强制使用) :

iss: jwt签发者

sub: jwt所面向的用户 

aud: 接收jwt的一方

exp: jwt的过期时间,这个过期时间必须要大于签发时间

nbf: 定义在什么时间之前,该jwt都是不可用的.

iat: jwt的签发时间

jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

payload-公共的声明 :

公共的声明可以添加任何的信息。一般这里我们会存放一下用户的基本信息(非敏感信息)。

payload-私有的声明 : 

私有声明是提供者和消费者所共同定义的声明。需要注意的是,不要存放敏感信息,不要存放敏感信息,不要存放敏感信息!!!

因为:这里也是base64编码,任何人获取到jwt之后都可以解码!! 

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

注意: sub和iat是标准声明,分别代表所面向的用户和jwt签发时间。

1、sub:这个是发给一个账号是1234567890的用户(也许是ID)

2、name:名字叫John Doe

3、iat:签发时间是1516239022(2030/1/18 9:30:22)

Signature 

这部分就是 JWT 防篡改的精髓,其值是对前两部分 base64UrlEncode 后使用指定算法签名生成,以默认 HS256 为例,指定一个密钥(secret),就会按照如下公式生成:

 

HMACSHA256(
 base64UrlEncode(header) + "." + base64UrlEncode(payload),
 secret,
)

注意: 算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"( . )分隔,就可以返回给用户。

JWT 的使用方式 

流程: 客户端收到服务器返回的 JWT,可以储存在 Cookie 里面,也可以储存在 localStorage。此后,客户端每次与服务器通信,都要带上这个 JWT。你可以把它放在 Cookie 里面自动发送,但是这样不能跨域,所以更好的做法是放在 HTTP 请求的头信息 Authorization 字段里面。 

实时效果反馈

1.客户端收到服务器返回的 JWT把数据保存到____。

A load

B session

C loadStorage

D 以上都是错误

2. JWT签证默认算法__。

A HS256 

B Base64

C HS384

D SR384

服务网关Gateway实现用户鉴权_用户微服务

创建cloud-auth-user6500工程 

引入POM依赖 

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
       <!-- eureka client 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

服务网关Gateway实现用户鉴权_JWT工具类

引入JWT依赖

<dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>fastjson</artifactId>
     <version>1.2.79</version>
</dependency>
<dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>3.7.0</version>
</dependency>

创建JWT工具类JWTUtils

public class JWTUtil {
    // 秘钥
    public static final String SECRET_KEY = "erbadagang-123456";
    // token过期时间
    public static final long TOKEN_EXPIRE_TIME = 5 * 60 * 1000;
    // 签发人
    private static final String ISSUER = "issuer";
    // 用户名
    private static final String USER_NAME = "username";
    
}

生成签名方法

  public static String token(String username) {
        Date now = new Date();
        //SECRET_KEY是用来加密数据签名秘钥
        Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
        String token = JWT.create()
                // 签发人
               .withIssuer(ISSUER)
                // 签发时间
               .withIssuedAt(now)
                // 过期时间
               .withExpiresAt(new Date(now.getTime() + TOKEN_EXPIRE_TIME))
                // 保存权限标记
               .withClaim(USER_NAME,username)
               .sign(algorithm);
        log.info("jwt generated user={}",username);
        return token;
   }

验证签名

public static boolean verify(String token)
{
        try {
            //SECRET_KEY是用来加密数据签名秘钥
            Algorithm algorithm = Algorithm.HMAC256(SECRET_KEY);
            JWTVerifier verifier = JWT.require(algorithm)
                   .withIssuer(ISSUER)
                   .build();
            //如果校验有问题会抛出异常。
            verifier.verify(token);
            return true;
       } catch (Exception ex) {
            ex.printStackTrace();
       }
        return false;
   }

测试JWT

public static void main(String[] args) {
       // 生成Token
        String token = JWTUtil.token("itbaizhan");
        System.out.println(token);
        
        //验证Token
        boolean verify = JWTUtil.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3N1ZXIiLCJleHAiOjE2NDUwNjMyNzYsImlhdCI6MTY0NTA2Mjk3NiwidXNlcm5hbWUiOiJpdGJhaXpoYW4ifQ.uKKVEMCTW0-e_bPHLyb-JY8CwRU7ciU8vP5B78lDY3s");
        System.out.println(verify);
   }

服务网关Gateway实现用户鉴权_用户服务实现JWT鉴权

编写LoginController类

@RequestMapping("user")
@RestController
@Slf4j
public class LoginController { }

编写统一返回实体类

/**
* AuthResult 作用 : 统一返回实体类
*/
@Data
@NoArgsConstructor
@Builder
public class AuthResult {
    // 返回状态码
    private int code;
    // 返回描述信息
    private String msg;
    // 返回Token签名
    private String token;
    public AuthResult(int i, String s) {
        this.code = i;
        this.msg = s;
   }
    public AuthResult(int i, String success, String token) {
        this.code = i;
        this.msg = success;
        this.token = token;
   }
}

编写用户登录接口

/**
     * 用户登录
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @PostMapping("/login")
    public AuthResult login(String username,String password) {
        // TODO 模拟数据库验证用户名密码
        if ("admin".equals(username) && "admin".equals(password)) {
            //生成token
            String token = JWTUtil.token();
            return new AuthResult(0, "success", token, refreshToken);
       } else {
            return new AuthResult(1001,"username or password error");
       }
   }

编写验证令牌接口

/**
     * 验证令牌
     * @param token 令牌
     * @return
     */
    @GetMapping("/verify")
    public AuthResult verify(String token) {
        // 验证令牌
        boolean success = JWTUtil.verify(token);
        if (success){
            return AuthResult.builder()
                   .code(200).msg("Token未失效").build();
       }else {
            return AuthResult.builder()
                   .code(500).msg("Token失效").build();
       }
   }

YML文件编写

eureka:
 client:
    # 表示是否将自己注册到Eureka Server
   register-with-eureka: true
    # 示是否从Eureka Server获取注册的服务信息
   fetch-registry: true
    # Eureka Server地址
   service-url:
     defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
 instance:
   instance-id: user-service
   prefer-ip-address: true
spring:
 application:
    # 设置应用名词
   name: user-service
server:
 port: 6510

Postman测试

测试登录

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/780205.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5分钟开发一个AI论文抓取和ChatGPT提炼应用

5分钟开发一个AI论文抓取和ChatGPT提炼应用 第一步 点击“即刻开始” -选择模板 python -修改标题 “AIPaper”&#xff0c;项目标识“AIPaper”&#xff0c;点击“创建项目” 第二步 在编程区域右侧AI区域&#xff0c;输入框输入以下内容&#xff1a; 请根据下面的内容&…

4.3 Bootstrap CSS编码规范

文章目录 Bootstrap CSS编码规范语法声明顺序不要使用 import媒体查询&#xff08;Media query&#xff09;的位置带前缀的属性单行规则声明简写形式的属性声明Less 和 Sass 中的嵌套注释class 命名选择器代码组织编辑器配置 Bootstrap CSS编码规范 语法 用两个空格来代替制表…

Autosar通信入门系列04-聊聊CAN通信的Basic-CAN与Full-CAN

本文框架 1. 概述2. 基本内容2.1 什么是Basic-CAN与Full-CAN&#xff1f;2.2 既生瑜何生亮&#xff1f; 3. 不同报文类型如何选择Basic-CAN与Full-CAN&#xff1f; 1. 概述 在CAN通信学习时我们经常会遇到或者听同事聊到Basic-CAN与Full-CAN&#xff0c;单从字面上很难理解两个…

计讯物联工业路由器基于5G LAN技术成为工业互联网发展的“加速器”

随着5G的成熟发展&#xff0c;其易部署、低时延、高可靠、大带宽、广连接的特性助力传统工业智能数字化转型&#xff0c;解决了传统工业的布线繁琐、通信环境复杂易造成干扰、对时延与稳定性更加敏感、移动通信的网络需求、海量设备互联等难题。然而&#xff0c;5G在工业制造领…

软件测试基础 - 自动化测试技术

目录 前言&#xff1a; 什么是自动化测试&#xff1f; 自动化测试的优势&#xff1a; 自动化测试的劣势&#xff1a; 适合实施测试自动化的项目&#xff1a; 推行自动化测试的阻力&#xff1a; 软件研发生命周期各个阶段的自动化测试技术 前言&#xff1a; 软件测试是一…

还在手动维护Yapi?

因前后端人员通过接口定义字段&#xff0c;返回值等对接时非常苦恼&#xff0c;没有一个很好的平台维护&#xff0c;后端每次迭代都要写开发文档&#xff0c;需求变化&#xff0c;多系统联调等&#xff0c;给前后端联调造成阻塞。 1、后端开发文档编写规范 1&#xff09;文档…

DataWhale AI夏令营——机器学习

DataWhale AI夏令营——机器学习 学习记录一1. 异常值分析2. 单变量箱线图可视化3. 特征重要性分析 学习记录一 锂电池电池生产参数调控及生产温度预测挑战赛 已配置环境&#xff0c;跑通baseline&#xff0c;并在此基础上对数据进行了简单的分析。 1. 异常值分析 对训练集…

Python知识使用目录体系

Python知识使用目录体系 前记&#xff1a;开始以Get No.方式进行记录&#xff0c;知识体系的建立 Get No. No1: IDEA&#xff08;Java主要编辑器&#xff09;中添加Python插件;(就在此总目录中写&#xff0c;属于纪念开始) 附加&#xff1a;另外一个pycharm工具使用python工…

pyqt5中的控件

字体部分 学习如何加载本地字体a.tff import sys from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton from PyQt5.QtGui import QFont, QFontDatabaseclass MyWindow(QWidget):def __init__(self):super().__init__()self.button Noneself.label None…

【Java开发】 Mybatis-Plus 06:通用枚举功能

枚举类是开发时绕不开的话题&#xff0c; Mybatis-Plus 也提供了简便的枚举功能&#xff0c;快学起来吧~ 目录 1 版本区别 2 通用枚举功能实现 2.1 创建枚举类 2.2 实体类新增枚举字段 3 枚举字段测试 3.1 新增 ① 后台指定枚举 ② 前后端交互 3.2 查询 3.3 修改 ①…

递归排序算法快速排序的实现过程

快速排序(Insertion Sort)也是一种递归排序算法。 快速排序原理&#xff1a;先以列表中的任意一个数为基准(一般选头或尾)&#xff0c;将列表分为左、右两个子列表。 左子列表的数要比基准数小&#xff0c;右子列表的数要比基准数大。然后继续把左子列表和右子列表按同样的方…

蓝桥杯专题-真题版含答案-【九宫幻方】【打鱼还是晒网】【阶乘尾数零的个数】【等差素数列】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

【Java】重写compareTo()方法给对象数组排序

我们先给一个数组排序&#xff0c;我们肯定用的是Arrays.sort()方法&#xff1a; public class test2 {public static void main(String[] args) {int[] arr{3,5,4,6,9,8,1};System.out.println(Arrays.toString(arr));System.out.println("---------");Arrays.sort…

【一文详解 requests 库中 json 参数和 data 参数的用法】

在requests库当中&#xff0c;requests请求方法&#xff0c;当发送post/put/delete等带有请求体 的请求时&#xff0c;有json和data2个参数可选。 众所周知&#xff0c;http请求的请求体格式主要有以下4种&#xff1a;application/jsonapplicaiton/x-www-from-urlencoded multi…

音视频开发-ffmpeg介绍-系列二

目录 一、FFmpeg核心结构体 二、解码流程 三、FFmpeg解码实现 四、FFmpeg编码实现 五、FFmpeg转码实现 一、FFmpeg核心结构体 AVFormatContext&#xff1a;解封装功能的结构体&#xff0c;包含文件名、音视频流、时长、比特率等信息&#xff1b; AVCodecContext&#xf…

nginx代理后刷新显示404,这样解决。

项目部署之后&#xff0c;通过首页进入访问页面正常&#xff0c;F5刷新之后出现错误如下图。 怎么解决&#xff1a; 在Nginx配置里面增加 location / {root /www/wwwroot/phm/phmweb;index index.html index.htm;try_files $uri $uri/ /index.html;}

Kotlin基础(七):数据类和封闭类

前言 本文主要讲解kotlin数据类&#xff08;DataClass&#xff09;和封闭类&#xff08;SealedClasses&#xff09;&#xff0c;包括使用数据类&#xff0c;对象复制&#xff0c;数据类成员的解构&#xff0c;使用封闭类&#xff0c;以及数据类和封闭类在Android开发中的应用。…

【数据挖掘】时间序列的傅里叶变换:用numpy解释的快速卷积

一、说明 本篇告诉大家一个高级数学模型&#xff0c;即傅里叶模型的使用&#xff1b; 当今&#xff0c;傅里叶变换及其所有变体构成了我们现代世界的基础&#xff0c;为压缩、通信、图像处理等技术提供了动力。我们从根源上理解&#xff0c;从根本上应用&#xff0c;这是值得付…

微信小程序——页面跳转方法和场景用法总结

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

失物招领小程序连接人与物的奇妙纽带

hello guys!! 随着生活的节奏加快&#xff0c;人们在各个领域都有可能会遇到丢失物品或者拾到物品的情况。不论是学生、员工还是旅游爱好者&#xff0c;我们都有可能在生活的轨迹中遇到这样的情况。为了提供一个便捷的平台&#xff0c;让人们能够分享、发布和寻找丢失物品&…