【JWT鉴权】如何来写一个token令牌认证登录?

news2024/11/19 5:43:36

目录

  • 一. 🦁 话题引入
    • 1.2 什么是JWT?
  • 二. 🦁 技术体现
    • 2.1 引入依赖
    • 2.2 编写JWT工具类
    • 2.3 编写登录方法
    • 2.4 编写JWT拦截器验证令牌
    • 2.5 编写要配置拦截的接口
  • 三. 🦁 话题终结

一. 🦁 话题引入

在做项目过程中,我们一般都是最先编写登录注册功能,登录功能最重要的是登录成功后,系统还会保存该登录用户信息,这种保存用户信息的逻辑可以有两种:

  1. 最简单的一种就是使用Session来保存用户信息,然后使用filter来验证用户是否登录,但是这种方法只能是单体架构的项目适用,性能也不会很好。在分布式项目中,会有很多子模块并且部署在不同的服务器中,这样是无法使用session保存的,因为sessio不能共享。
  2. 使用单点登录技术就能很好地解决这个弊端。
  • 单点登录(Single Sign On)简称为 SSO。即在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。JWT是一种常用的单点登录解决方案。

1.2 什么是JWT?

JWTJson Web Token的简称,是一种令牌生成算法。使用JWT能够保证Token的安全性,且能够进行Token时效性的检验。使用JWT时,登录成功后将用户信息生成一串令牌字符串。将该字符串返回给客户端,客户端每次请求时都在请求头携带该令牌字符串。在其他模块验证令牌,通过则证明用户处于登录状态,并拿到解析后的用户信息,未通过证明用户处于未登录状态。

二. 🦁 技术体现

要实现JWT鉴权,就得实现如下步骤:

  • 引入JWT工具类,编写生成令牌和解析令牌的方法。
  • 用户登录成功后生成令牌字符串返回给前端。
  • 前端每次请求时都在请求头带入令牌字符串。
  • 在通用模块编写拦截器,解析请求头中的令牌字符串。
  • 在Api模块配置拦截器,配置拦截器拦截哪些接口,即这些接口需要登录才能访问。

现在来编写代码实现

2.1 引入依赖

<dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>

2.2 编写JWT工具类

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.itbaizhan.shopping_common.exception.BusException;
import com.itbaizhan.shopping_common.pojo.ShoppingUser;
import com.itbaizhan.shopping_common.result.CodeEnum;

import java.util.Date;

public class JWTUtil {
    //token过期时间,一天
    private static final Long EXPIRE_DATE = 1000*60*60*24L;
    // 秘钥
    private static final String SECRET = "jackie";
    // 签发者
    private static final String ISSUER = "JACKIE";

    /**
     * 签名生成
     * @param shoppingUser
     * @return
     */
    public static String sign(ShoppingUser shoppingUser){
        String token = JWT.create()
                .withIssuer(ISSUER) // 签发者
                .withIssuedAt(new Date()) // 签发时间
                .withExpiresAt(new Date(new Date().getTime() + EXPIRE_DATE)) // 过期时间
                .withSubject(shoppingUser.getUsername()) // 保存用户名
                .withClaim("userId",shoppingUser.getId()) // 保存用户id
                .sign(Algorithm.HMAC256(SECRET)); // 秘钥
        return token;
    }

    /**
     * 签名解析
     * @param token 签名字符串
     * @return 解析得出的用户名
     */
    public static String verify(String token){
        try {
            String username = JWT
                    .require(Algorithm.HMAC256(SECRET))
                    .withIssuer(ISSUER)
                    .build()
                    .verify(token)
                    .getSubject();
            return username;
        } catch (Exception e){
            throw new BusException(CodeEnum.VERIFY_TOKEN_ERROR);
        }
    }

    /**
     * 签名解析,获取用户id
     * @param token 签名字符串
     * @return 用户id
     */
    public static Long getId(String token){
        try {
            Long userId = JWT
                    .require(Algorithm.HMAC256(SECRET))
                    .withIssuer(ISSUER)
                    .build()
                    .verify(token)
                    .getClaim("userId")
                    .asLong();
            return userId;
        } catch (Exception e){
            throw new BusException(CodeEnum.VERIFY_TOKEN_ERROR);
        }
    }
}

这个utils有三个方法,一个是生成token字符串,一个是解析该字符串获取登录的用户名,还要就是获取登录用户的id。

2.3 编写登录方法

如果使用Session存储用户信息,在验证完名字和密码后,直接将该登录对象setAttribute(“users”,users)里面。

在这里插入图片描述

而使用单点登录,则是直接调用JWTUtil.sign(user),生成JWT令牌,返回该令牌给前端用户。
标准代码:

服务层:

 @Override
    public String loginPassword(String username, String password) {
        // 1.验证用户名
        QueryWrapper<ShoppingUser> queryWrapper = new QueryWrapper();
        queryWrapper.eq("username",username);
        ShoppingUser shoppingUser = shoppingUserMapper.selectOne(queryWrapper);
        if (shoppingUser == null){
            throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);
        }
        // 2.验证密码
        boolean verify = Md5Util.verify(password, shoppingUser.getPassword());
        if (!verify){
            throw new BusException(CodeEnum.LOGIN_NAME_PASSWORD_ERROR);
        }
        // 3.生成JWT令牌,返回令牌
        String sign = JWTUtil.sign(shoppingUser);
        return sign;
    }

控制层

 /**
     * 用户名密码登录
     * @param shoppingUser 用户对象
     * @return 登录结果
     */
    @PostMapping("/loginPassword")
    public BaseResult loginPassword(@RequestBody ShoppingUser shoppingUser){
        String sign = shoppingUserService.loginPassword(shoppingUser.getUsername(), shoppingUser.getPassword());
        return BaseResult.ok(sign);
    }

2.4 编写JWT拦截器验证令牌

这里验证令牌的方式是拦截所有的请求,如果 JWTUtil.verify(token)不抛异常则通过这个请求。

// 拦截器,验证令牌
public class JWTInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 获取请求头中的token
        String token = request.getHeader("token");
        // 验证令牌
        JWTUtil.verify(token);
        return true;
    }
}

2.5 编写要配置拦截的接口

我们在用户模块配置该模块要拦截的接口(如果是单体架构,拦截器和该部分可以写在一起)。

除了这种方式,还有一种编写方式,你想知道吗?

在User模块先实例化一个InterceptorConfig配置类,实现WebMvcConfigurer接口,将上面写的拦截器在addInterceptor(new JWTInterceptor())方法里面实例化,然后拦截所有的接口( .addPathPatterns(“/**”)),再放行不需要认证的接口。

// 拦截器配置
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new JWTInterceptor())
                .addPathPatterns("/**") // 拦截的接口
                .excludePathPatterns(
                       "填写需要放行的接口url"
                ); //放行的接口
    }
}

至此,一个令牌认证就完成啦。

三. 🦁 话题终结

又一篇业务逻辑类的文章表述,希望路过的您看到了觉得还行,给个三连哦 🌹。

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

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

相关文章

vue-element-ui前后端交互实现分页查询

大体思路&#xff1a; ①添加element-ui分页组件 ②在data里定义几个参数用来存放当前页&#xff0c;每页条数&#xff0c;条目总数以及存放后端分页查询的结果 ③后端使用分页查询&#xff0c;controller层接收当前页以及每页条数的参数 ④前端编写方法发送请求到controll…

用jsp实现简单登入注册界面功能(css美化)(软件idea)

思路&#xff1a;创建登入界面&#xff08;login&#xff09;&#xff0c;再创建登入成功与登入失败界面&#xff08;loginsuccess与loginfail&#xff09;&#xff0c;再创建注册成功界面&#xff08;registersuccess&#xff09;与注册界面&#xff08;register&#xff09;以…

用HTML实现简易版计算器

计算器功能&#xff1a;实现了加减乘除、清零、回退、四则运算、幂运算、根式运算等等。 运行结果如下&#xff1a; 引入的图片&#xff1a;back.png HTML部分&#xff1a;用table表格添加计算器的按键&#xff0c;给每个按键设置一个相应的单击事件&#xff0c;点击一个按键后…

RuoYi-Vue——图标使用

使用若依的小伙伴们&#xff0c;是否有遇到找图标的烦恼。若依框架里图标分两种&#xff0c; 1.用在表格中的图标&#xff1a; 2.用在菜单及个人信息的图标&#xff1a; 下面我就针对这两种图标给大家总结一下。 1.表格图标&#xff08;ElementUI图标Icon&#xff09; 若依的表…

【JavaScript】五个常用功能/案例:判断特定结尾字符串 | 获取指定字符串 | 颜色字符串转换 | 字符串转驼峰格式 | 简易购物车

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 &#x1f5a5;️ NodeJS专栏&#xff1a;Node.js从入门到精通 &#x1f5a5;️ 博主的前端之路&#xff1a;前端之行&#xff0c;任重道远&#xff08;来自大三学长的万字自述&#xff09; &#x1f5a5;️ TypeScript知识总…

layui数据表格的使用(前端和后端)

数据表格&#xff08;纯前端&#xff09; 快速使用 首先需要引入layui的css和js <link rel"stylesheet" href"../static/layui/css/layui.css"> <script src"../static/layui/layui.js" charset"utf-8"></script>…

如何搭建vue框架-1

提示&#xff1a;前端新人&#xff0c;初来乍到&#xff0c;若文章写的不好大家多包涵。 文章目录前言一、vue是什么&#xff1f;二、ElementUI是什么&#xff1f;三、搭建前的准备四、安装步骤1.安装webpack2.安装vue-cli3.通过vue-cli构建项目4.启动项目5.其他总结前言 基于…

element-ui表格编辑

前言&#xff1a; 准备&#xff1a; element-uivue3vscode 实现步骤&#xff1a; 数据标定打开激活编辑保存 1. 设定需要编辑的表格单元格是否编辑标识 在请求后台表格数据时进行一个二次包装&#xff0c;如果后端已经处理则不需要在进行包装&#xff08;此处包装是否编辑…

手撕前端面试题【javascript~模板字符串、类继承、参数解析器、生成页码等】

前端的那些基本标签&#x1f353;&#x1f353;模板字符串&#x1f353;&#x1f353;类继承&#x1f353;&#x1f353;参数解析器&#x1f353;&#x1f353;生成页码&#x1f353;&#x1f353;js中哪些操作会造成内存泄漏?html页面的骨架&#xff0c;相当于人的骨头&#…

react router6.x官方DEMO

Tutorial v6.4.2 | React Router 初始化项目 import React from "react"; import ReactDOM from "react-dom/client"; import {createBrowserRouter,RouterProvider,Route, } from "react-router-dom"; import "./index.css";const …

用CSS设置颜色、背景和图像效果

&#x1f4dc;个人简介 ⭐️个人主页&#xff1a;微风洋洋&#x1f64b;‍♂️ &#x1f351;博客领域&#xff1a;编程基础&#x1f4a1;,后端&#x1f4a1;,大数据,信息安全 &#x1f345;写作风格&#xff1a;干货,干货,还是tmd的干货 &#x1f338;精选专栏&#xff1a;【J…

js数组常用方法(19种)|你会的到底有多少呢?

一、改变原数组的方法 1.push&#xff08;&#xff09; 末尾添加数据 语法: 数组名.push(数据) 作用: 就是往数组末尾添加数据 返回值: 就是这个数组的长度 //push var arr [10, 20, 30, 40] res arr.push(20) console.log(arr);//[10,20,30,40,20] console.log(res);//52. …

【Cesium】使用TLE轨道两行数计算轨道信息,并生成CZML格式文件

TLE为轨道两行数&#xff0c;简单的说是用两行数字表示轨道的相关信息&#xff0c;本文即用轨道两行数来计算任一时刻卫星的位置信息和速度信息&#xff0c;并生成CZML文件能够读取的格式 1、satellite.js库简介 简而言之&#xff0c;satellite.js库可以根据TLE轨道两行数&…

vue 项目适配笔记本1920*1080 125%缩放

前言 在台式机上开发pc端项目时&#xff0c;由于是1920*1080的分辨路和100缩放&#xff0c;看起来是没有问题。在笔记本上有问题 因为现在很多14寸的笔记本&#xff0c;出厂默认就是125%或150%的显示。导致很多时候我们的项目&#xff0c;自己开发的时候都是按照100%比例来开发…

Vue使用Serial连接串口

本来只是随手记录一下&#xff0c;发现看的人多了&#xff0c;想着还是修复一下bug吧&#xff0c;供各位看官指正 2022-10-24本次更新: 1、修复在不支持Serial的情况下&#xff0c;控制台报错 2022-09-19本次更新: 1、修复了传输数据接收分隔的情况(增加数据缓存) 2、修复串口连…

【中兴】web训练营~一文带你走进前端 | 百图制作

&#x1f4e2;作者简介&#xff1a;物联网领域创作者&#xff0c;&#x1f3c5;阿里云专家博主&#x1f3c5; &#x1f3c5;华为云享专家&#x1f3c5; ✒️个人主页&#xff1a;Choice~ &#x1f310;格言&#xff1a;可正因为难&#xff0c;才有价值&#xff01;&#x1f536…

Linux 使用Nginx部署web(vue、react)项目

前言 本文基于&#xff1a;操作系统 CentOS 7.6 使用的工具&#xff1a;Xshell7、Xftp7 1.安装所需依赖 安装gcc yum -y install gcc安装pcre、pcre-devel yum -y install pcre pcre-devel安装zlib、zlib-devel yum install -y zlib zlib-devel安装openssl、openssl-dev…

【uni-app】点击左上角返回按钮,弹出弹窗或者是携带参数返回上一页

目录 1、弹出弹窗 2、把这一页的数据带回到上一页&#xff08;获取下一页的数据 &#xff09; 3、跳转页面并携带参数&#xff0c;接受页获取参数 1、弹出弹窗 当我返回上一页的时候需要做一个判断是否需要保存 onBackPress 只支持APP和H5 但不支持小程序 &#xff0c;可以…

Java web—访问http://localhost:8080/xx/xx.jsp报404错误问题

由于我们在eclipse ee中把项目部署在web端经常会出现报404错误。 原因为&#xff1a; 404状态码是一种http状态码&#xff0c;其意思是&#xff1a; 所请求的页面不存在或已被删除。通俗的讲就是当用户输入了错误的链接时&#xff0c;返回的页面。 以下描述几种情况&#xff1a…

IDEA从零到精通(24)之lombok插件的安装与使用

文章目录作者简介引言导航概述安装插件使用小结导航热门专栏推荐作者简介 作者名&#xff1a;编程界明世隐 简介&#xff1a;CSDN博客专家&#xff0c;从事软件开发多年&#xff0c;精通Java、JavaScript&#xff0c;博主也是从零开始一步步把学习成长、深知学习和积累的重要性…