前言

  相信大家在进行用户认证中或多或少都要对用户进行认证,当前进行认证的方式有基于session、token等主流方式,但是目前使用最广泛的还是基于JWT的用户认证,特别适用于前后端分离的项目。

本篇博客我将简要的讲解JWT(Json web token)的只要知识点并实现简单的认证,如果我哪些方面有问题,请大家激烈评论,我好进一步修改!

1.Jwt的组成

  将Jwt是由头部Header、载荷payload、以及签名sign三个部分组成

  1.1 Herder

     头部包含签名的生成token的'typ'以及'alo'也就是签名的类型和哪一种算法,还有签名中部分的编码格式

  1.1 payload

        载荷中存储部分用户的信息,但是最好不要将密码存储在载荷中,因为头部以及载荷安全性不高

  1.1 sign

     JWT的安全性体现在签名中,它是由头部、载荷以及盐进行Base64加密而成的,中间使用“.”连接,最后使用头部的编码格式编码得到签名。因为头部和载荷的安全性较低,所以我们主要通过盐来防止token伪造,一般通过

     HMAC256算法对其进行加密

2.Jwt的认证流程

  上述图详细地叙述了通过JWT进行认证的过程

  1)用户第一次在浏览器网页里面输入用户名和密码进行认证,当客户端收到用户信息后对用户信息进行验证

  2)客户端对用户信息验证无误后,返回一个token给浏览器

  3)用户下次登录的时候携带这个token进行登录

  4)客户端验证token无误后就放行

  5)服务端返回用户访问客户端资源

3.Jwt的实现

  3.1 生成token

private static final long EXPIRE_TIME = 1800L;//单位为秒
private static final String TOKEN_SECRET = "woToken"; /**
* 生成token
* @param sysUser
* @return
*/
public static String sign(SysUser sysUser){
String token = null; try {
Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME * 1000);
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");
token = JWT.create()
.withHeader(map)//添加头部
.withIssuer("auth0")
.withClaim("uid", sysUser.getUid())//载体中设置uid
.withClaim("username", sysUser.getUsername())//载体中设置username
.withExpiresAt(expireDate)//设置过期时间
.withIssuedAt(new Date())//设置签发时间
.sign(Algorithm.HMAC256(TOKEN_SECRET));//secret加密
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (JWTCreationException e) {
e.printStackTrace();
}
return token;
}

生成token

  3.2 验证token

/**
* 校验token并解析token
*/
public static Boolean verifyToken(String token){
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
DecodedJWT decodedJWT = verifier.verify(token);
return true;
} catch (JWTVerificationException e) {
e.printStackTrace();
return false;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
}
}

验证token

  3.3 获取token中的uid

/**
* 获取token中的payload信息
* @param token
* @return
*/
public static Integer getUid(String token){
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("uid").asInt();
} catch (JWTDecodeException e) {
return null;
}
}

获取载荷信息

package com.ku.wo.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.ku.wo.entity.SysUser; import java.util.Date;
import java.util.HashMap;
import java.util.Map; /**
* 生成Jwt和认证
*/
public class JwtUtils { private static final long EXPIRE_TIME = 1800L;//单位为秒
private static final String TOKEN_SECRET = "woToken"; /**
* 生成token
* @param sysUser
* @return
*/
public static String sign(SysUser sysUser){
String token = null; try {
Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME * 1000);
Map<String, Object> map = new HashMap<>();
map.put("alg", "HS256");
map.put("typ", "JWT");
token = JWT.create()
.withHeader(map)//添加头部
.withIssuer("auth0")
.withClaim("uid", sysUser.getUid())//载体中设置uid
.withClaim("username", sysUser.getUsername())//载体中设置username
.withExpiresAt(expireDate)//设置过期时间
.withIssuedAt(new Date())//设置签发时间
.sign(Algorithm.HMAC256(TOKEN_SECRET));//secret加密
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (JWTCreationException e) {
e.printStackTrace();
}
return token;
} /**
* 校验token并解析token
*/
public static Boolean verifyToken(String token){
try {
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).withIssuer("auth0").build();
DecodedJWT decodedJWT = verifier.verify(token);
return true;
} catch (JWTVerificationException e) {
e.printStackTrace();
return false;
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
}
} /**
* 获取token中的payload信息
* @param token
* @return
*/
public static Integer getUid(String token){
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("uid").asInt();
} catch (JWTDecodeException e) {
return null;
}
} }

JWT生成、校验、获取载荷信息全部代码

  3.4 拦截请求

package com.ku.wo.interceptor;

import com.ku.wo.utils.JwtUtils;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* 用于获取token并校验
*/ /**
* 单体项目验证token使用拦截器,分布式项目使用网关
*/
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// //不使用JWT使用的登录
//// if (request.getSession().getAttribute("uid") == null){
//// return false;//如果这里为false,后面的都不执行,并且postHandle()方法也不执行
//// }
//// return true; if(HttpMethod.OPTIONS.toString().equals(request.getMethod())){
System.out.println("OPTIONS请求,放行!");
return true;
} String token = request.getSession().getAttribute("token").toString();
System.out.println("拦截器的token获取"+token);
// String token = request.getHeader("token");
if(JwtUtils.verifyToken(token)){
return true;
}
//失败时返回失败信息
return false;
}
}

拦截请求

  3.5 拦截资源

package com.ku.wo.config;

import com.ku.wo.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.ArrayList;
import java.util.List; @Configuration
public class WebConfig implements WebMvcConfigurer { @Autowired(required = false)
LoginInterceptor loginInterceptor; @Override
public void addInterceptors(InterceptorRegistry registry) {
//创建拦截器对象 //白名单
List<String> patterns = new ArrayList<>();
patterns.add("/user/reg");
patterns.add("/user/login");
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/**")//默认对所有请求进行拦截
.excludePathPatterns(patterns);
} }

拦截资源

  3.6 controller执行

@PostMapping("/login")//在浏览器上面应该改为get
public JsonResult<String> login(@RequestParam(value = "name", required = false) String username,
@RequestParam(value = "pwd", required = false) String password, HttpSession session){
SysUser data = userDetailsService.login(username, password);
String token = JwtUtils.sign(data);
session.setAttribute("token", token);
session.setAttribute("user", data);
session.setAttribute("uid",data.getUid());
session.setAttribute("username", username);
return new JsonResult<String>(OK, token);
} @PostMapping("/get_login_data")//在浏览器上面应该改为get
public JsonResult<SysUser> getLoginData(String token, HttpSession session){
if(!session.getAttribute("token").equals(token)){
return new JsonResult<>(ERROR);
}
SysUser data = (SysUser)session.getAttribute("user");
return new JsonResult<SysUser>(OK, data);
} //JSONResult响应类
package com.ku.wo.utils; import lombok.Data; import java.io.Serializable; @Data
//原文使用的是<E>因为属性data属于元素,但是我在网上找到使用T貌似更好,
// 尝试一下使用T的情况怎么样,List<T>表示集合中元素都为T类型,网上使用的大多数也是T
public class JsonResult<T> implements Serializable {
private Integer state;
private String message;
private T data;
//必须要有无参构造
public JsonResult(){
super();
}
public JsonResult(Integer state){
super();
this.state = state;
} public JsonResult(Throwable e){//Throwable是error和Exception的父类,里面有getMessage()方法获取错误和异常信息
super();
this.message = e.getMessage();
} public JsonResult(Integer state, T data){
super();
this.state = state;
this.data = data;
}
}

controller测试方法

4.Jwt测试

5.参考链接

https://blog.csdn.net/m0_56966142/article/details/123398543?ops_request_misc=&request_id=&biz_id=102&utm_term=%E4%BD%BF%E7%94%A8JWT%E5%AE%9E%E7%8E%B0%E7%94%A8%E6%88%B7%E8%AE%A4%E8%AF%81&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-123398543.142^v63^control_1,201^v3^control_2,213^v2^t3_esquery_v2&spm=1018.2226.3001.4187

Springboot整合Jwt实现用户认证的更多相关文章

  1. SpringBoot整合JWT实现登录认证

    什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...

  2. SpringBoot集成JWT实现权限认证

    目录 一.JWT认证流程 二.SpringBoot整合JWT 三.测试 上一篇文章<一分钟带你了解JWT认证!>介绍了JWT的组成和认证原理,本文将介绍下SpringBoot整合JWT实现 ...

  3. Node.js 使用JWT进行用户认证

    代码地址如下:http://www.demodashi.com/demo/13847.html 运行环境 该项目基于 node(v7.8.0版本以上) 和 mongodb 数据库,因此电脑上需要安装这 ...

  4. ASP.NET Core 2.2 : 二十六. 应用JWT进行用户认证

    本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案(ASP.NET Core 系列目录) 一.什么是JWT? JWT(json web token ...

  5. 应用JWT进行用户认证及Token的刷新

    本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案(ASP.NET Core 系列目录) 一.什么是JWT? JWT(json web token ...

  6. ASP.NET Core 2.2 : 二十六. 应用JWT进行用户认证及Token的刷新

    来源:https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_26.html 本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及T ...

  7. DRF使用JWT进行用户认证

    1. 首先需要安装第三方依赖包 pip install djangorestframework-jwt 2. 在Django的settings文件中 配置全局的JWT认证类 REST_FRAMEWOR ...

  8. 教你 Shiro + SpringBoot 整合 JWT

    本篇文章将教大家在 shiro + springBoot 的基础上整合 JWT (JSON Web Token) 如果对 shiro 如何整合 springBoot 还不了解的可以先去看我的上一篇文章 ...

  9. 前后端分离下用jwt做用户认证

    0 前后端分离下的用户信息认证 前端使用Vue+axios,后端使用SpringBoot+SpringSecurity. 为了解决http无状态的问题,我采用jwt(json web token)保存 ...

  10. SpringBoot整合Shiro 四:认证+授权

    搭建环境见: SpringBoot整合Shiro 一:搭建环境 shiro配置类见: SpringBoot整合Shiro 二:Shiro配置类 shiro整合Mybatis见:SpringBoot整合 ...

随机推荐

  1. 实验8 python库应用编程与体验

    3.实验任务3 from turtle import * def square(size=50, rgb='orange'): '''绘制正方形 参数size指定边长 参数rgb指定画笔颜色 如果没有 ...

  2. Vue router前端路由配置以及实现tab切换

    vue router 安装:npm install vue-router或cnpm install vue-router或yarn add vue-router. 安装完成之后会在package.js ...

  3. ROS2踩坑记录

    在Windows10的WSL2中的Ubuntu22.04子系统中安装ros2 humble版本. 官方文档http://docs.ros.org/en/humble/Installation/Ubun ...

  4. LOJ数列分块入门九题(上)

    一转眼,已经有整整一年没有在博客园写博客了.去洛谷写了几篇(How time flys. 最近突然想起其实我不太擅长分块算法,又想起去年暑假有位同学同我提起过LOJ的数列分块九题,说来惭愧,打了这么久 ...

  5. 【Unity】Lua热重载

    写在前面 本文讨论的"Lua热重载"是基于他人现成工具和相关博文上展开的,所以这里并不会重复实现一遍工具,主要记录我的理解过程. Lua热重载 探索 偶然在知乎上翻到一篇文章&qu ...

  6. Otto Group Product Classification

    遇到的坑: 做多分类,用CrossEntropyLoss时,训练时候的正确标签的范围应该是[0,n-1],而不是[1,n],不然会报 IndexError: Target is out of boun ...

  7. [Python]判断字符串是否是数值,可以采用正则表达式技术来进行输入检测处理

    判断字符串是否是数值的传统代码参考: sInput=input("请输入数值[整数或小数]:") sInput2="" bErr=False cSign=&qu ...

  8. Hive:FAILED: LockException [Error 10280]: Error communicating with the metastore

    1.问题示例 使用hive直接选择查看表中数据报错,而相同语句在spark-sql却不报错. 实在无力吐槽hive了,因它受伤太多了. (1)使用hive hive (test)> select ...

  9. week3题解

    1.寄包柜 看到题目最容易想到开二位数组 但数据量过大,因此需要map #include <bits/stdc++.h> using namespace std; map<int,m ...

  10. delphi中判断IP地址输入的合法性

    function GetSubStrCount(sSubStr, sParentStr: string): integer; begin Result := 0; while Pos(UpperCas ...