Web应用程序的身份验证:Session认证、Token认证

2023-05-16

一、Web应用程序的身份验证

1、Session认证

① 用户向服务器发送用户名和密码

② 服务器验证通过后,在当前对话(session)里面保存相关数据,如用户角色,登陆时间等

③ 服务器向用户返回一个session_id,写入用户的Cookie

④ 用户随后的每一次请求,都会通过Cookie,将session_id传回服务器

⑤ 服务器收到session_id,找到前期保存的数据,由此得知用户的身份

认证流程:

 

        Session认证的方式扩展性不好,如果是服务器集群,或者是跨域的服务导向架构,就要求session数据共享,以便每台服务器都能够读取session,针对这问题有两种解决方案:

        ① session数据持久化,写入数据库或别的持久层。优点是架构清晰,但工程量大

        ② 服务器不再保存session数据,所有数据都保存在客户端,每次请求都发回服务器。Token就是其中一个代表

2、Token认证

Token是在服务端产生的一串字符串,是客户端访问资源接口(API)时所需要的资源凭证

        ① 客户端使用用户名和密码请求登陆,服务端收到请求,去验证用户名和密码

        ② 验证成功后,服务端会签发一个token并把这个token发送给客户端

        ③ 客户端收到token后,存储起来,比如放在cookie或者localStorage里头

        ④ 客户端每次向服务端请求资源时需要带上这个token

        ⑤ 服务端收到请求后去验证这个token,成功则返回请求数据

 

实现方式:JWT(JSON Web Token)认证

原理:

① 用户发送用户名和密码后,服务器认证并生成JWT令牌(JSON对象),将其发回给客户端

 (为了防止用户篡改数据,服务器在生成这个对象的时候会加上签名)

② 客户端将JWT令牌存储在本地以便后续使用

③ 当客户端向另一个域名服务器发送请求时,将JWT令牌作为请求头(放在Authorization字段里头)或请求参数发送

④ 服务器收到请求后,检查JWT令牌的有效性,并进行身份验证和授权

⑤ 若令牌有效则返回请求的数据,否则返回未授权的错误信息

JWT由三个部分组成:

1、Header(头部):

{
  "alg": "HS256", // 令牌类型
  "typ": "JWT" //加密算法 
}

2、Payload(负载):

{
  "iss": "example.com",
  "sub": "1234567890",
  "aud": ["foo", "bar"],
  "exp": 1648696800,
  "nbf": 1648693200, // 2022年4月29日10:20:00
  "iat": 1648694700,
  "jti": "abcdef123456"
}
// 1、iss(issuer): 表示JWT签发者的名称,通常是一个字符串或URL。
// 2、sub(subject): 表示JWT的主题,即客户端的唯一标识符,通常是一个用户ID。
// 3、aud(audience): 表示JWT的预期接收者,即对该JWT有效的接收方,可以是单个字符串或一个字符串数组。
// 4、exp(expiration time): 表示JWT的过期时间,用Unix时间戳表示。
// 5、nbf(not before): 表示JWT的生效时间,用Unix时间戳表示。
// 6、iat(issued at): 表示JWT的签发时间,用Unix时间戳表示。
// 7、jti(JWT ID): 表示JWT的唯一标识符,通常用于避免重放攻击。

3、Signature(签名):由Header、Payload和一个密钥(secret,存储在服务器端,对外不可见)进行签名生成。

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

将Header、Payload和Signature通过'.'连接在一起形成JWT令牌,例如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

代码实现:

① 引入依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

② 添加JWT配置

# JWT相关配置
jwt.secret=your-secret
jwt.expiration=3600

③ 创建JWT工具类:用于生成和解析JWT

@Component
public class JwtUtils {
​
    // 秘钥
    @Value("${jwt.secret}")
    private String secret;
​
    // 过期时间,单位秒
    @Value("${jwt.expiration}")
    private Long expiration;
​
    // 生成JWT
    public String generateToken(Long userId) {
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes()); // 创建密钥
        Date now = new Date();
        Date expireTime = new Date(now.getTime() + expiration * 1000);
        return Jwts.builder()
                .setIssuer("issuer") // 设置JWT的签发者
                .setAudience("audience") // 设置JWT的接收方
                .setSubject(userId.toString()) // 设置JWT的主题
                .setIssuedAt(now) // 设置JWT的签发时间
                .setExpiration(expireTime) // 设置JWT的过期时间
                .signWith(key, SignatureAlgorithm.HS256) // 用HS256算法和密钥key签名JWT
                .compact(); // 生成JWT字符串
    }
​
    // 解析JWT
    public Claims parseToken(String token) {
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes()); // 创建密钥
        return Jwts.parserBuilder()
                .setSigningKey(key) // 设置用于解析JWT的密钥
                .build()
                .parseClaimsJws(token) // 解析JWT,获取Jws<Claims>实例
                .getBody();
    }
}

  

④ 配置拦截器:用于验证请求中的JWT是否有效

@Component
public class JwtInterceptor implements HandlerInterceptor {
​
    @Autowired
    private JwtUtils jwtUtils;
​
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从请求头中获取token
        String token = request.getHeader("Authorization");
        // 判断token是否存在并以Bearer开头
        if (token != null && token.startsWith("Bearer ")) { 
            token = token.substring(7); // 去掉token前缀
            Claims claims = jwtUtils.parseToken(token); // 解析JWT
            if (claims != null) {
                Long userId = Long.valueOf(claims.getSubject()); // 获取JWT中的用户id
                // 将用户信息存储到request中,方便后续操作
                request.setAttribute("userId", userId);
                return true;
            }
        }
        // 解析失败,返回401未授权状态码
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        return false; // 拦截请求
    }
}
 

⑤ 使用JWT

@RestController
@RequestMapping("/api")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody UserLoginDto userLoginDto) {
        // 用户登录逻辑
    
        // 生成 JWT token
       String token = Jwts.builder()
            .setSubject(user.getUsername()) // 主题
            .claim("roles", user.getRoles()) 
            .setIssuedAt(new Date()) // 签发时间
            .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) // 过期时间
            .signWith(SignatureAlgorithm.HS512, SECRET_KEY) // 使用算法和密钥对token进行签名。
            .compact(); // 将JWT token生成为字符串
    
       // 返回 token 给客户端
       return ResponseEntity.ok(new AuthResponse(token));
    }
​
    
    @GetMapping("/users")
    @PreAuthorize("hasAuthority('ROLE_ADMIN')") // 拥有 ROLE_ADMIN 权限的用户才能访问该方法
    public ResponseEntity<?> getUsers(@RequestHeader("Authorization") String    authorizationHeader) {
        String token = authorizationHeader.substring(7); // 去掉 "Bearer" 前缀
    
        // 验证 token 是否有效
        Claims claims = Jwts.parser() // 获取一个JwtParser对象
                .setSigningKey(SECRET_KEY) // 设置JWT的签名密钥,用于校验JWT的合法性
                .parseClaimsJws(token) // 将其转化为Jws对象
               .getBody(); // 获取Jws对象中的payload信息
    
        // 获取用户列表逻辑
}
​
    
    @GetMapping("/users/{id}")
    public ResponseEntity<?> getUserById(@PathVariable Long id) {
        // 根据用户ID获取用户信息逻辑
    }
    
    // 省略其他接口...
}

  

Session和Token认证的区别:

        Session和Token都是常用的用户认证方式,它们的作用都是为了验证用户身份和授权访问资源,但是它们的实现方式有所不同。

        Session是一种服务器端认证方式,通常通过在服务器端保存用户的登录信息(较安全),以便在后续的请求中进行验证。当用户进行登录操作时,服务器会创建一个Session,并给这个Session分配一个唯一的标识符(Session ID),然后将这个Session ID发送给客户端保存。客户端在后续的请求中需要携带这个Session ID,服务器端根据这个Session ID来查找对应的Session,从而验证用户的身份。

        Token是一种无状态认证方式,通常通过在客户端保存用户的登录信息(不安全),以便在后续的请求中进行验证。当用户进行登录操作时,服务器会生成一个Token,并将这个Token发送给客户端保存。客户端在后续的请求中需要携带这个Token,服务器端通过验证这个Token来确定用户的身份。

优缺点:

        Session需要在服务器端保存用户的登录信息,因此需要占用服务器的资源,并且需要在分布式系统中进行Session共享和Session失效管理(工程量大)。

        Token是无状态的,不需要在服务器端保存用户的登录信息,因此具有良好的可扩展性,并且可以很方便地实现分布式系统中的认证和授权。用解析token的计算时间换取session的存储空间,从而减轻服务器压力,减少频繁查询数据库

        Session的安全性比较高,因为Session的内容保存在服务器端,客户端无法直接修改Session的内容

        Token的安全性相对较低,因为Token的内容保存在客户端,客户端可以通过一些手段来篡改Token的内容。

Session和Token的应用场景:

        一般来说,使用 session 可能更适合传统的 Web 应用,因为它通常需要用户在浏览器中持续地与应用交互,而且涉及到敏感数据的处理。例如,在电子商务网站中,用户需要登录才能访问个人购物车和订单等敏感信息,此时可以使用 session 来验证用户身份,并在服务器端存储相关的用户信息和状态。

        而在 API (应用程序编程接口)设计和单页面应用中,使用 token 可能更加常见。由于 API 和单页面应用的特性,客户端可以直接与 API 或后端服务通信,而不需要经过浏览器的中间层。此时,使用 token 可以避免一些 session 的问题,如跨域和服务器负载均衡等。同时,token 也更容易在不同服务之间进行传递和共享,比如使用 OAuth2 等协议来实现单点登录和授权等功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Web应用程序的身份验证:Session认证、Token认证 的相关文章

  • 记录个人编译DCNv2的过程(windows 10,vs2019, torch1.7.0)

    小白一个 xff0c 因为配FairMOT环境需要用到DCNv2 xff0c 就简单记录一下自己遇到的问题和解决方法 如有错误 xff0c 请多指教 首先主要参考了博客https blog csdn net Ningmoua article
  • 初识CMMI2.0

    初识 CMMI2 0 xff08 以下内容根据网络知识学习和整理而成 xff09 正式发布与获取 xff1a 2018 年 3 月 8 日 xff0c CMMI2 0 正式版本正式上线全新的主页 xff08 https cmmiinstit
  • C++编写杨辉三角

    xff08 1 xff09 美观很重要 xff0c 哈哈哈 include lt iostream gt include lt iomanip gt using namespace std int YangHuiData int n n是杨
  • IP地址的分类及范围详解:A、B、C、D、E五类是如何划分的

    IP地址类型 最初设计互联网络时 xff0c 为了便于寻址以及层次化构造网络 xff0c 每个IP地址包括两个标识码 ID xff0c 即网络ID和主机ID 同一个物理网络上的所有主机都使用同一个网络ID xff0c 网络上的一个主机 包括
  • iscsiadm命令基本用法

    发现目标 iscsiadm m discovery t sendtargets p 192 168 1 1 3260 m discovery 指定模式为discovery p 192 168 1 1 3260 指定目标ip和端口 登入节点
  • linux内核中的睡眠函数*delay、*sleep

    目录 一 睡眠函数种类 1 原子上下文 2 非原子上下文 二 使用环境 1 使用环境的不同 xff0c 选择不同的延时 2 驱动机制不同 3 内核中的计算函数执行的函数 三 实测两类函数的延时以及原因 1 测试系统中的睡眠函数 2 输出结果
  • RTOS 和裸机系统的异同-基于 ESP32 学习双核 FreeRTOS 的使用

    Learning FreeRTOS with esp32 什么是 RTOS 其本质上是运行在小型嵌入式设备上的特殊软件 系统软件 如同手机的安卓系统软件 windows 系统软件 RTOS VS 裸机系统 传统的裸机系统 xff08 无操作
  • FreeRTOS 创建第一个任务

    创建第一个任务 概述 创建任务的函数为 xff1a BaseType t span class token function xTaskCreate span span class token punctuation span TaskFu
  • ACL功能的实现

    ACL 看控制访问列表 xff08 Access Control List xff09 控制指定的用户能否通过指定的接口访问本机的服务 http https ftp ssh telnet xff0c 举个例子 xff1a 没开启ACL功能前
  • STM32 USB 虚拟串口演练

    记录一下 xff0c STM32官方虚拟串口走通流程 第一步 xff0c 在CSDN寻找经验 xff0c 结合实际情况进行计划 为了节省读者时间 xff0c 推荐写的比较好的博文 地址如下 xff1a http blog csdn net
  • Linux smbclient使用详情

    例子 smbclient 192 168 10 2 目录 U 用户名 回车 再输入 密码 参数说明 网络资源 网络资源 的格式为 服务器名称 资源分享名称 密码 输入存取网络资源所需的密码 B lt IP地址 gt 传送广播数据包时所用的I
  • ESP8266获取网络天气

    使用ESP8266模块来获取网络数据 xff08 天气 xff0c 时间等 xff09 xff0c 还是挺简单的 一步一步来 1 初始化串口与相关IO 使得MCU可正常使用串口的发送与接收 xff0c 以及一些IO控制ESP8266的使能端
  • win11环境安装postgreSql数据库

    1 xff0c 下载安装文件后一路next安装 2 数据库初始化 创建data目录 xff0c 保证软件有权限读写和访问 pg ctl D data init 3 启动数据库 pg ctl D data D data start 4 创建初
  • verilog实现38译码器

    module decode 38 input wire 2 0 a output reg 7 0 y integer i always 64 begin for i 61 0 i lt 8 i 61 i 43 1 begin if a 61
  • DiffServ--百度介绍

    区分服务 xff08 DiffServ xff09 是IETF工作组为了克服Inter Serv的可扩展性差在1998年提出的另一个服务模型 xff0c 目的是制定一个可扩展性相对较强的方法来保证IP的服务质量 与综合服务 xff08 In
  • P2P在NAT和防火墙上的穿透

    概述 本文主要讨论关于P2P通信的一些常见问题和解决方案 主要内容包含 xff1a P2P通信与网络设备的关系 不同的网络设备特征对P2P产生的影响 网络地址转换 xff08 NAT xff09 的类型 NAT类型的检测方法 协议防火墙的突
  • conflicting types for 'dev_t'的原因

    在Linux下编译程序有时会遇到这种问题 xff0c 这貌似是一个Linux历史遗留问题 usr include sys types h 62 error conflicting types for dev t usr include li
  • https不能访问时的解决方案

    当 xff08 win7 里 xff09 IE浏览器 https打不开 https不能访问时 1 请保证 IE 工具 高级选项中的TSL 1 0前面不要打上勾就可以了 xff08 注解 xff0c 当你用 IE的 还原高级设置 时 xff0
  • Ubuntu LTS 版本知多少

    原文地址http oss org cn html 79 n 70179 html 特别声明 xff1a 从Ubuntu 12 04开始 xff0c LTS 版本的支持周期策略有所改变 xff0c 具体改变信息见下面的详细说明 先介绍一词 x
  • ubuntu下配置vlan功能--官网vlan how to

    http ubuntuforums org showthread php t 61 703387 ubuntu官网介绍 802 1q VLAN HOWTO Doing 802 1q trunking to an Ethernet switc

随机推荐

  • 万台规模下的SDN控制器集群部署实践

    目前在网络世界里 xff0c 云计算 虚拟化 SDN NFV这些话题都非常热 今天借这个机会我跟大家一起来一场SDN的深度之旅 xff0c 从概念一直到实践一直到一些具体的技术 本次分享分为三个主要部分 xff1a SDN amp NFV的
  • linux-vdso.so.1介绍

    这段时间看Linux内核源码的时候 xff0c 经常碰到vdso这个东西 像在Feature fixup中 xff0c 获取时间等操作时 xff0c 网上搜了一下 xff0c 才知道了含义 xff0c 原来这是Linux为了解决和glibc
  • ECC密钥编程举例,并用它做签名和验签,并生成共享密钥

    下面的例子生成两对ECC密钥 xff0c 并用它做签名和验签 xff0c 并生成共享密钥 include lt string h gt include lt stdio h gt include lt openssl ec h gt inc
  • 最新OmniPeek无线驱动详细列表与下载说明/支持捉空口包的网卡

    OmniPeek无线驱动详细列表与下载 在进行无线网络分析时 xff0c Omnipeek需要安装特殊驱动来捕获管理 控制和数据帧 而且在OmniPeek停止不用时 xff0c 它们将作为普通驱动支持网络服务的正常运行 WildPacket
  • Html自我介绍

    lt doctype html gt lt html gt lt head gt lt meta charset 61 34 utf 8 34 gt lt title gt 兰博基尼 lt title gt lt style type 61
  • grub2下常见系统初始化错误的分析和解决

    原文连接http tieba baidu com p 2910461207 grub rescue gt grub gt initramfs 是开机错误时 xff0c 常见到的状况 我将分以下几个部份说明 xff1a 一 开机出现 grub
  • MSP-EXP430F5529LP: Error initializing emulator: No USB FET was found

    正常情况下 xff0c 安装了CCS之后 xff0c TI MSP430LaunchPad的驱动都可以自动安装好 主要是 xff1a MSP Application UART 和 MSP Debug Interface 当然 xff0c 非
  • CMakeLists.txt加载第三方库

    生成一个库文件 TgMath h ifndef TGMATH H define TGMATH H include 34 tgmath global h 34 class TGMATHSHARED EXPORT TgMath public T
  • ROS学习之订阅消息——Subscriber_代码分析

    接上篇 xff1a ROS学习之发布消息 Publisher 详解版本 xff1a 本代码文件名为 xff1a subscriber cpp include 34 ros ros h 34 include 34 std msgs Strin
  • LXC 介绍

    转自 xff1a https www cnblogs com xidongyu p 5767020 html LXC又名Linux container xff0c 是一种虚拟化的解决方案 xff0c 这种是内核级的虚拟化 主流的解决方案Xe
  • openstack原生网络和SDN网络对比

    1 原生Neutron架构图 xff1a 2 Networking odl的架构 3 ODL 处理过程 当OpenStack Neutron API接收到用户创建网络等操作请求 xff0c 它会调用ML2的相关方法 ML2已经定义了post
  • 树莓派 Raspberry Pi 3B+安装官方系统(一)

    两年前购买的树莓派 xff08 可看当时我的记录树莓派 3B 43 重装系统并配置 WiFi YouForever xff09 已经在角落里吃灰了好长时间 xff0c 一度以为已经损坏 xff0c 几天前试着拿出来折腾一下 xff0c 竟然
  • Rime——最好的输入法

    同步发布在博客 xff1a https www zhyong cn 9422 最近迷上了五笔输入法 xff0c 于是想找一款好用的五笔输入法软件 xff0c 最终确定鼎鼎大名的Rime输入法 一款跨平台的开源输入法 xff0c 支持Wind
  • Haar特征描述算子-人脸检测

    Haar特征描述算子 人脸检测 详细资料 3 1简介 Haar like特征最早是由Papageorgiou等应用于人脸表示 xff0c 在2001年 xff0c Viola和Jones两位大牛发表了经典的 Rapid Object Det
  • HTML(css+div)登录界面

    xff08 1 xff09 这是当时做的一个课程设计 xff0c 很多人想要图片 xff0c 在这里我把用到的所有图片资源分享下 xff08 2 xff09 链接 xff1a https pan baidu com s 1nUX1DQe a
  • 基于Matlab的GPU加速---for循环处理

    采用GPU加速时 xff0c 如遇for循环 xff0c 则很容易增加代码在GPU上运行的时间开销 在编程时 xff0c 使用矩阵和向量操作或arrayfun bsxfun pagefun替换循环操作来向量化代码 1 arrayfun函数
  • android ndk extern "C"

    C 43 43 的代码里面 xff1a extern 34 C 34 这是因为生成的二进制文件中 xff0c C和C 43 43 的符号表不相同造成的 Jni是按照C的生成规则去找函数的 xff0c 所以要加上extern C使编译器把函数
  • AdaBoost中利用Haar特征进行人脸识别算法分析与总结1——Haar特征与积分图

    目前因为做人脸识别的一个小项目 xff0c 用到了AdaBoost的人脸识别算法 xff0c 因为在网上找到的所有的AdaBoost的简介都不是很清楚 xff0c 让我看看头脑发昏 xff0c 所以在这里打算花费比较长的时间做一个关于Ada
  • 智能驾驶仿真场景构建技术

    随着汽车智能化程度的不断提高 xff0c 智能汽车通过环境传感器与周边行驶环境的信息交互与互联更为密切 xff0c 需应对的行驶环境状况也越来越复杂 xff0c 包括行驶道路 周边交通和气象条件等诸多因素 xff0c 具有较强的不确定性 难
  • Web应用程序的身份验证:Session认证、Token认证

    一 Web应用程序的身份验证 1 Session认证 用户向服务器发送用户名和密码 服务器验证通过后 xff0c 在当前对话 xff08 session xff09 里面保存相关数据 xff0c 如用户角色 xff0c 登陆时间等 服务器向