首页 > 其他分享 >后台管理系统的通用权限解决方案(八)认证机制介绍、JWT介绍与jjwt框架的使用

后台管理系统的通用权限解决方案(八)认证机制介绍、JWT介绍与jjwt框架的使用

时间:2024-10-30 15:18:34浏览次数:3  
标签:body jwt JWT 介绍 jjwt 签名 put new

文章目录

1 认证机制介绍

1.1 HTTP Basic Auth

HTTP Basic Auth 是一种简单的登录认证方式,Web浏览器或其他客户端程序在请求时,通过HTTP请求头提供用户名和密码。简单点说就是每次请求时都提供用户的用户名和密码。

这种方式是先把 用户名:密码 拼接起来,并将得出的结果字符串用Base64算法编码。

例如,提供的用户名是 bill ,密码是 123456 ,则拼接后的结果就是 bill:123456 ,然后再将其用Base64编码,得到 YmlsbDoxMjM0NTY= 。最终将Base64编码的字符串通过HTTP请求头发送出去,由服务器解码得到一个由冒号分隔的用户名和密码的字符串。

优点: 基本上所有流行的网页浏览器都支持基本认证。

缺点: 由于用户名和密码都是Base64编码的,而Base64编码是可逆的,所以用户名和密码可以认为是明文。所以只有在客户端和服务器主机之间的连接是安全可信的前提下才可以使用。

1.2 Cookie-Session Auth

Cookie-Session 认证机制是通过浏览器保存的Cookie对象与服务器端的Session对象匹配来实现状态管理。

第一次请求认证时,在服务器端创建一个Session对象,同时在用户的浏览器端创建了一个Cookie对象;当我们关闭浏览器的时候,Cookie会被删除。但可以通过修改Cookie的过期事件使Cookie在一定时间内有效。

优点: 相对HTTP Basic Auth更加安全。

缺点: 随着不同客户端用户的增加,独立的服务器已无法承载更多的用户。

1.3 OAuth

OAuth 是一个关于授权(authorization)的开放网络标准。它允许用户提供一个令牌,而不是用户名和密码来访问服务器。

严格来说,OAuth不是一个标准协议,而是一个安全的授权框架。它详细描述了系统中不同角色、用户、服务前端应用(比如API),以及客户端(比如网站或移动App)之间怎么实现相互认证。

OAuth 工作流程如下图:

优点: 快速开发,代码量小,维护工作少。

缺点: OAuth有海量的资料需要学习,要完全理解需要花费大量时间。OAuth不是一个严格的标准协议,因此在实施过程中更容易出错。

1.4 Token Auth

基于 Token 的认证鉴权机制类似于 HTTP 协议,也是无状态的。这种方式不需要在服务端保留用户的认证信息或者会话信息。这就意味着基于 Token 的认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

这个 Token 必须要在每次请求时传递给服务端,它应该保存在请求头中,Token Auth 流程如下图:

优点:

  • 支持跨域访问
  • Token 机制在服务端不需要存储Session信息:Token 自身包含了所有登录用户的信息,只需要在客户端的Cookie或本地介质存储状态信息
  • 去耦:不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你可以进行Token生成调用即可
  • 更适用于移动应用:Cookie是不被客户端(iOS, Android,Windows 8等)支持的。
  • 基于标准化:API可以采用标准化的 JSON Web Token (JWT)。这个标准已经存在多个后端库(.NET, Ruby, Java, Python, PHP)和多家公司的支持(如:Firebase, Google, Microsoft)

缺点:

  • 占带宽:正常情况下要比 session_id 更大,需要消耗更多流量,挤占更多带宽,假如你的网站每月有 10 万次的浏览量,就意味着要多开销几十兆的流量。听起来并不多,但日积月累也是不小一笔开销。实际上,许多人会在 JWT 中存储的信息会更多
  • 无法在服务端注销,因为服务端是无状态的,并没有保存客户端用户登录信息
  • 对于有着严格性能要求的 Web 应用并不理想,尤其对于单线程环境

2 JWT

2.1 JWT介绍

JWT全称为JSON Web Token,是目前最流行的跨域身份验证解决方案。 JWT是为了在网络应用环境间传递声明而制定的一种基于JSON的开放标准。

JWT特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可被加密。

2.2 JWT的数据结构

JWT其实就是一个很长的字符串,字符之间通过"."分隔符分为三个子串,各子串之间没有换行符。每一个子串表示了一个功能块,总共有三个部分:JWT头(header)有效载荷(payload)签名(signature),如下图所示:

2.2.1 JWT头

JWT头是一个描述JWT元数据的JSON对象,通常如下所示:

{"alg": "HS256", "typ": "JWT"}
  • alg:表示签名使用的算法,默认为HMAC SHA256(写为HS256)
  • typ:表示令牌的类型,JWT令牌统一写为JWT

最后,使用Base64 URL算法将上述JSON对象转换为字符串。

JWT签名算法中,一般有两个选择:HS256和RS256。

HS256 (带有 SHA-256 的 HMAC )是一种对称加密算法,双方之间仅共享一个密钥。由于使用相同的密钥生成签名和验证签名, 因此必须注意确保密钥不被泄密。

RS256 (采用SHA-256 的 RSA 签名) 是一种非对称加密算法, 它使用公钥/私钥对。JWT的提供方采用私钥生成签名, JWT的使用方获取公钥以验证签名。

2.2.2 JWT有效载荷

有效载荷,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。

有效载荷部分规定有如下七个默认字段供选择:

iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT

除以上默认字段外,还可以自定义私有字段。

最后,同样使用Base64 URL算法将有效载荷部分JSON对象转换为字符串。

2.2.3 JWT签名

签名实际上是一个加密的过程,是对上面两部分数据通过指定的算法生成哈希,以确保数据不会被篡改。

首先需要指定一个密钥(secret),该密钥仅仅保存在服务器中,并且不能向用户公开。然后使用JWT头中指定的签名算法(默认情况下为HMAC SHA256),根据以下公式生成签名哈希:

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

在计算出签名哈希后,JWT头、有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。

3 jjwt

3.1 jjwt介绍

jjwt 是一个提供JWT创建和验证功能的Java库。永远免费和开源(Apache License,版本2.0),很容易使用和理解。

3.2 jjwt案例

  • 1)创建maven工程jjwt-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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hsgx</groupId>
    <artifactId>jjwt-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>
    </dependencies>
</project>
  • 2)编写单元测试,测试jjwt的特性
package com.hsgx.test;

import cn.hutool.core.io.FileUtil;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.Test;

import java.io.DataInputStream;
import java.io.InputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

public class JwtTest {

    //生成jwt,不使用签名
    @Test
    public void test1(){
        //添加构成JWT的参数
        Map<String, Object> headMap = new HashMap();
        headMap.put("alg", "none");//不使用签名算法
        headMap.put("typ", "JWT");

        Map<String, Object> body = new HashMap();
        body.put("userId","1");
        body.put("username","xiaoming");
        body.put("role","admin");
        String jwt = Jwts.builder()
                .setHeader(headMap)
                .setClaims(body)
                .setId("jwt001")
                .compact();
        System.out.println(jwt);

        //解析jwt
        Jwt result = Jwts.parser().parse(jwt);
        Object jwtBody = result.getBody();
        Header header = result.getHeader();
        System.out.println(result);
        System.out.println(jwtBody);
        System.out.println(header);
    }

    //生成jwt时使用签名算法生成签名部分----基于HS256签名算法
    @Test
    public void test2(){
        //添加构成JWT的参数
        Map<String, Object> headMap = new HashMap();
        headMap.put("alg", SignatureAlgorithm.HS256.getValue());//使用HS256签名算法
        headMap.put("typ", "JWT");

        Map<String, Object> body = new HashMap();
        body.put("userId","1");
        body.put("username","xiaoming");
        body.put("role","admin");

        String jwt = Jwts.builder()
                .setHeader(headMap)
                .setClaims(body)
                .setId("jwt001")
                .signWith(SignatureAlgorithm.HS256,"hsgx")
                .compact();
        System.out.println(jwt);

        //解析jwt
        Jwt result = Jwts.parser().setSigningKey("hsgx").parse(jwt);
        Object jwtBody = result.getBody();
        Header header = result.getHeader();
        System.out.println(result);
        System.out.println(jwtBody);
        System.out.println(header);
    }

    //生成jwt时使用签名算法生成签名部分----基于RS256签名算法
    @Test
    public void test3() throws Exception{
        //添加构成JWT的参数
        Map<String, Object> headMap = new HashMap();
        headMap.put("alg", SignatureAlgorithm.RS256.getValue());//使用RS256签名算法
        headMap.put("typ", "JWT");

        Map body = new HashMap();
        body.put("userId","1");
        body.put("username","xiaoming");
        body.put("role","admin");

        String jwt = Jwts.builder()
                .setHeader(headMap)
                .setClaims(body)
                .setId("jwt001")
                .signWith(SignatureAlgorithm.RS256, getPriKey())
                .compact();
        System.out.println(jwt);

        //解析jwt
        Jwt result = Jwts.parser().setSigningKey(getPubKey()).parse(jwt);
        Object jwtBody = result.getBody();
        Header header = result.getHeader();

        System.out.println(result);
        System.out.println(jwtBody);
        System.out.println(header);
    }

    //获取私钥
    public PrivateKey getPriKey() throws Exception{
        InputStream resourceAsStream =
                this.getClass().getClassLoader().getResourceAsStream("pri.key");
        DataInputStream dis = new DataInputStream(resourceAsStream);
        byte[] keyBytes = new byte[resourceAsStream.available()];
        dis.readFully(keyBytes);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePrivate(spec);
    }

    //获取公钥
    public PublicKey getPubKey() throws Exception{
        InputStream resourceAsStream =
                this.getClass().getClassLoader().getResourceAsStream("pub.key");
        DataInputStream dis = new DataInputStream(resourceAsStream);
        byte[] keyBytes = new byte[resourceAsStream.available()];
        dis.readFully(keyBytes);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePublic(spec);
    }

    //生成自己的 秘钥/公钥 对
    @Test
    public void test4() throws Exception{
        //自定义 随机密码,  请修改这里
        String password = "itcast";

        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        SecureRandom secureRandom = new SecureRandom(password.getBytes());
        keyPairGenerator.initialize(1024, secureRandom);
        KeyPair keyPair = keyPairGenerator.genKeyPair();

        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();

        FileUtil.writeBytes(publicKeyBytes, "d:\\pub.key");
        FileUtil.writeBytes(privateKeyBytes, "d:\\pri.key");
    }
}

本节完,更多内容查阅:后台管理系统的通用权限解决方案

延伸阅读:后台管理系统的通用权限解决方案(七)SpringBoot整合SpringEvent实现操作日志记录(基于注解和切面实现)

标签:body,jwt,JWT,介绍,jjwt,签名,put,new
From: https://blog.csdn.net/weixin_42739799/article/details/143265427

相关文章

  • ccs的介绍,安装和使用入门
    第一章:ccs的介绍,下载和安装01:ccs介绍工欲善其事必先利其器,如果你正在打算学习DSP,那么需要准备以下三个东西:1)DSP开发板,当然任何具有DSP最小系统的板子都是可以的;2)仿真器,仿真器用来将程序烧写到DSP中,同时具备在线仿真调试的功能;3)编译环境CCS,有了它你就可以很方便的写程序了......
  • 英锐芯 | 功放芯片介绍
    01功放的定义功放其实是功率放大器的简称02功放的作用其作用主要是将音频器材输入的较微弱信号进行放大后,产生足够大的电流去推动扬声器进行声音的重放。03功放的分类A类、B类、AB类、D类、F类、G类等1、甲类功放(A类):是指在信号的整个周期内(正弦波的正负两个半周),......
  • HarmonyOS:自由流转介绍
    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤博客园地址:为敢技术(https://www.cnblogs.com/strengthen/ )➤GitHub地址:https://github.com/strengthen➤原文地址:https://www.cnblogs.com/strengthen/p/18515669➤如果链接不是为敢技术的博客园地址,则可能是......
  • GaussDB数据库基础函数介绍2
    二、GaussDB常用基础函数介绍与示例1、数字操作函数在GaussDB数据库中,数字操作函数是指用于执行数字操作的函数,例如加减乘除、取余、幂运算等。这些函数通常在数学、计算机科学和工程学等领域中使用,用于处理数字数据和执行数字操作。以下是一些常见的数字操作函数:--abs(x)--......
  • GaussDB数据库基础函数介绍1
    前言函数是数据库中最基本的组成部分之一,它们用于定义和操作数据库中的表格、记录、索引和视图等对象。在数据库中,函数的作用非常重要,因为它们可以实现数据的复杂操作,如查询、更新、删除和排序等。作为华为自主创新研发的分布式关系型云数据库,GaussDB也拥有强大的函数支持体系。......
  • 深圳保税区服务功能介绍
    保税仓储、运输、报关于一体,为广大客户提供方便、安全、快捷、*节约成本的优质配套物流服务。提供转厂和转口服务、代理一般贸易进/出口手续、仓储配送服务、简单加工、检测、拼箱作业,承接境内外海关监管货物,保税货物及一般货物陆路运输服务,提供海关业务咨询及在区内办厂业务咨......
  • C#学习 [类型系统] 基本类型介绍(10)
    在变量中指定类型声明变量但不初始化inti;MyClassm;声明且初始化inti=0;MyClassm=newMyClass();方法中参数与返回值指定类型publicintgetValue(inti){returni;}内置变量C#提供了一组标准的内置类型,这些类型可供在任何C#程序中使用。基本......
  • 磐启微电子公司介绍和产品选型表
       磐启微电子是一家面向智慧物联网、工业互联网的无线通信芯片设计企业。成立于2010年,总部位于中国上海,并在苏州和深圳分别设立了研发中心及分公司 拥有百余人的团队,研发人员占比超过75%。核心团队多来自于国内外顶尖高校和科研机构。拥有专利超200余项。    ......
  • SQL注入介绍
    初探SQL注入的分类、挖掘技巧以及防御的方法漏洞介绍(1)注入条件用户能控制输入且输入的内容被带到数据库去执行(2)注入原理对用户输入过滤不严谨。(3)注入本质违背了“数据与代码分离”的原则(4)可能存在注入的SQL语句地方select语句输入payload,最后加注释符即可。inse......
  • dotnet core微服务框架Jimu介绍
    jimu是一个基于.Net6.0简单易用的微服务框架,参考了很多开源库以及想法,使用了大量的开源库(如DotNetty,consul.net,Flurl.Http,Json.net,Log4net,Quartz.net...),支持分布式、高并发和负载均衡,实现了服务治理(如服务注册、发现、健康检测...)和RPC调用。jimu(积木),正......