JWT入门教程

article/2025/9/14 17:09:29

简介

JWT,JSON Web Token,开放的、行业标准(RFC 7519),用于网络应用环境间安全传递声明。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的业务逻辑所须的声明信息。
特点:

  • 跨语言:支持主流语言
  • 自包含:包含必要的所有信息,如用户信息和签名等
  • 易传递:很方便通过HTTP头部传递

具体来说:

  1. JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次
  2. JWT 不加密的情况下,不能将秘密数据写入 JWT
  3. JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数
  4. JWT的最大缺点:由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或更改 token 的权限。即一旦签发JWT,在到期之前就会始终有效,除非服务器部署额外的逻辑
  5. JWT 本身包含认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证
  6. 为减少盗用,JWT应使用HTTPS协议传输

JWT的工作流程
在这里插入图片描述

组成

JWT的token是三段由小数点分隔组成的字符串:header.payload.signature,即头部、载荷与签名。Base64编码各个字符串。Base64用64个字符来表示任意二进制数据的方法,常用于URL、Cookie、网页中传输少量二进制数据。

header

头部包含两部分:声明类型和使用的散列算法(通常直接使用HMAC SHA256,就是HS256)

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

将头部进行base64编码构成第一部分。

payload

也称为JWT claims,放置需要传输的信息,有三类:

  • 保留claims,主要包括iss发行者、exp过期时间、sub主题、aud用户等
  • 公共claims,定义新创的信息,比如用户信息和其他重要信息
  • 私有claims,用于发布者和消费者都同意以私有的方式使用的信息

JWT规定7个官方字段,供选用:

  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):面向的用户
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号,唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

支持定义私有字段,示例:

{
"iss": "jwt.io",
"exp": 1496199995458,
"name": "johnny",
"role": "admin"," 
}

JWT默认是不加密的,任何人都可以读到,所以不要把隐私敏感信息放在这个部分。

signature

需要采用编码的header、编码的payload、secret,使用header中指定的算法进行签名。
对头部以及载荷内容进行签名。

适用场景

  1. 向Web应用传递一些非敏感信息
  2. 用户认证和授权系统
  3. Web应用的单点登录

实战

引入类库jjwt(jwt的Java实现版):

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

JwtUtil.java工具类,有3个工具类方法:根据用户名(一般是域账户)和用户ID生成jwt token,解析JWT token,根据登录态解析并获取该token对应的用户信息。记住,需要替换base64Security、clientId、jwtName3个变量,

package com.aaa.utils;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;public class JwtUtil {private final static String base64Security = "";private final static String clientId = "";private final static String jwtName = "";/*** 过期时间,2天*/private final static long TTLMillis = 172800 * 1000;/*** 解析jwt*/public static Claims parseJWT(String token) {if (StringUtils.isBlank(token) || !token.contains(".")) {return null;}try {return Jwts.parser().setSigningKey(DatatypeConverter.parseBase64Binary(base64Security)).parseClaimsJws(token).getBody();} catch (Exception e) {return null;}}public static String createJWT(String name, Integer userId) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);//生成签名密钥byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());// 添加构成JWT的参数JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT").claim("unique_name", name).claim("userid", userId).setIssuer(jwtName).setAudience(clientId).signWith(signatureAlgorithm, signingKey);// 添加Token过期时间if (TTLMillis >= 0) {long expMillis = nowMillis + TTLMillis;Date exp = new Date(expMillis);builder.setExpiration(exp).setNotBefore(now);}// 生成JWTreturn builder.compact();}public static Claims getUserInfo() {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();final String authHeader = request.getHeader("authorization");final String token = authHeader.substring(7);try {return JwtUtil.parseJWT(token);} catch (Exception e) {return null;}}
}

JWTInterceptor.java,登录态拦截器,request为空或非法,则跳转到登录页面;随后,request解析JWT token失败,依然是跳转到登录页面,解析成功,将JWT token信息再通过request.setAttribute()存入Request中。

package com.aaa.filter;import com.aaa.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class JWTInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {final String authHeader = request.getHeader("authorization");String url = request.getRequestURL().toString();String[] urls = url.split("/");String root = urls[0] + "/" + urls[1] + "/" + urls[2];// OPTIONS方法放行if ("OPTIONS".equals(request.getMethod())) {response.setStatus(HttpServletResponse.SC_OK);return true;} else {boolean checkAuth = null == authHeader || !authHeader.startsWith("Bearer") || authHeader.length() < 7;if (checkAuth) {response.sendRedirect(root);return false;}}final String token = authHeader.substring(7);try {final Claims claims = JwtUtil.parseJWT(token);if (claims == null) {response.sendRedirect(root);return false;}request.setAttribute("CLAIMS", claims);return true;} catch (final Exception e) {response.sendRedirect(root);return false;}}@Overridepublic void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {}@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {}
}

UserServiceImpl.java用户登录类,先根据LDAP来校验用户名和密码信息,校验通过后,将用户的域名信息和用户ID信息生成JWT token。

package com.aaa.service.user.impl;import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.aaa.dao.UserMapper;
import com.aaa.model.User;
import com.aaa.service.user.UserService;
import com.aaa.utils.DomainUtil;
import com.aaa.utils.JwtUtil;
import com.aaa.utils.ServiceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import java.util.List;
import java.util.Map;@Service
public class UserServiceImpl implements UserService {@Autowiredprivate UserMapper userMapper;@Overridepublic String login(JSONObject jsonObject) {String name = (String) jsonObject.get("userName");String pass = (String) jsonObject.get("password");if (StringUtils.isEmpty(name) || StringUtils.isEmpty(pas)) {return JSONObject.toJSONString(ServiceUtil.returnError("用户名或密码不能为空!"));}try {User user = new User(name, "1", true);// 手动在db里面配置新增用户User userInfo = userMapper.selectBySelectiveFields(user);if (userInfo == null) {return JSONObject.toJSONString(ServiceUtil.returnError("用户名不存在!"));}Boolean status = DomainUtil.checkDomain("CORP\\" + name, pass);if (status) {String jwtToken = JwtUtil.createJWT(userInfo.getUserName(), userInfo.getId());JSONObject data = new JSONObject();data.put("jwtToken", jwtToken);data.put("roleId", userMapper.getUserRole(userInfo.getId()));return JSONObject.toJSONString(ServiceUtil.returnSuccessData(data));} else {return JSONObject.toJSONString(ServiceUtil.returnError("用户名或者密码错误!"));}} catch (Exception e) {return JSONObject.toJSONString(ServiceUtil.returnError("系统异常,请稍后再试!"));}}
}

DomainUtil.checkDomain()方法,根据LDAP协议服务来校验用户的登录认证(域账户和电脑开机密码,此密码一般情况下会依据公司的安全部门要求3个月更新一次)

/*** 内网ldap账户认证*/
public static Boolean checkDomain(String userName, String password) {String url = "ldap://" + ldapIp + ":" + ldapPort;Hashtable<String, String> env = new Hashtable<>();javax.naming.directory.DirContext ctx;env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");env.put(Context.SECURITY_AUTHENTICATION, "simple");env.put(Context.PROVIDER_URL, url);env.put(Context.SECURITY_PRINCIPAL, userName);env.put(Context.SECURITY_CREDENTIALS, password);try {// 初始化上下文ctx = new javax.naming.directory.InitialDirContext(env);ctx.close();// 验证成功返回namereturn true;} catch (javax.naming.AuthenticationException e) {logger.error("认证失败:" + e.getMessage());return false;} catch (Exception e) {logger.error("认证出错:" + e.getMessage());return false;}
}

对比

token的认证和session认证

参考


http://chatgpt.dhexx.cn/article/7WCwurTj.shtml

相关文章

JT项目-1

DAY01 学习京淘的意义 1 为什么选择电商项目作为java培优部分的重要项目 火(用户量广) 技术难点多,高(高并发,高可用)尤其是在中国 谷歌是全球并发最高的网站 学习成本低(无需精通业务部分) 2 学习完京淘项目对我们的就业有什么好处 代替1-2年工作经验 技术就业范…

JWT --- 入门学习

不知道为什么,不用springboot test测试或者启动类启动,会报这个错误,找不到类路径 1.常见的认证机制 basic auth &#xff1a; 每次请求都会携带用户的username&#xff0c;password&#xff0c;易被黑客拦截。 Cookie auth : 我们请求服务器&#xff0c;创建一个session对象,…

Jetty

本文介绍一个使用Jetty开发的Web的小例子。 Jetty是一个开源的servlet容器&#xff0c;它为基于Java的web容器&#xff08;例如JSP和servlet&#xff09;提供运行环境。可以把它理解为和Tomcat一样&#xff0c;不过Jetty更小更轻量级。如果想更深入学习Jetty推荐看&#xff1a…

JWT入门详解

目录 一、JWT简介 1.什么是JWT&#xff1f; 2.为什么要使用JWT&#xff1f; 二、JWT的工作原理 三、JWT的组成 1.Header&#xff08;头部&#xff09; 2.Payload(载荷) Reserved claims(保留) Public claims&#xff08;公有&#xff09; Private claims(私有) 3.s…

Ubuntu系统搭建后端Websocket服务器--基于Apache Tomcat

目录 一、概述二、基本安装2.1 Java安装2.2 Apache Tomcat安装2.3 Eclipse EE安装 三、正式部署3.1 创建一个简单java web项目3.2 服务端部署3.3 运行3.4 局域网连接Websocket 一、概述 本文针对Ubuntu系统&#xff08;Win10下的虚拟机&#xff09;进行详述&#xff0c;本文测…

部署Nginx+Tomcat+Php-fpm+mariadb主主

要求 1、前端1台Nginx&#xff0c;均衡后端2台php-fpm&#xff0c;均衡后端2台Tomcat&#xff0c;2台MYSQL采用主主架构&#xff0c;用户通过域名访问前端Nginx 域名v1.jd.com v2.jd.com访问到Discuz和Jforum不同的网站。 2、将第一道题目的部署步骤和架构图画出来。架构图上要…

【JavaWeb】WEB开发概述以及Tomcat

&#x1f50e;这里是【JavaWeb】&#xff0c;关注我学习JavaWeb不迷路 &#x1f44d;如果对你有帮助&#xff0c;给博主一个免费的点赞以示鼓励 欢迎各位&#x1f50e;点赞&#x1f44d;评论收藏⭐️ &#x1f440;专栏介绍 【JavaWeb】 目前主要更新JavaWeb&#xff0c;一起…

tomcat环境搭和管理及实现jsp通过tomcat连接mysql

25.1 什么是Tomcat 官方网站&#xff1a;http:#tomcat.apache.org/ Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。由于有了 Sun 的参与和支持…

Tomcat的Https设置及Http自动跳转Https (Linux环境下)

1.场景还原 近期项目中要对信息传输过程中进行安全加密&#xff0c;那么第一时间浮现笔者脑海的当然是https,接下来笔者将介绍如何在web服务器Tomcat中配置Https及Http自动跳转Https 2.Https相关介绍 Https是由NetScape公司设计的一个基于Http的加密传输协议&#xff0c;可以这…

六、Tomcat集群

TOMCAT集群 目录 TOMCAT集群 1 1 集群 1 1.1 什么是集群 1 1.2 集群的特性 1 1.3 集群的分类 1 1.4 TOMCAT集群配置的优缺点 2 1.5 APACHETOMCAT 2 1.6 环境说明 2 2 软件安装 3 2.1 安装说明 3 2.2 JDK安装 3 2.3 APACHE安装 4 2.4 TOMCAT安装 4 3 集群配置 6 3.1 APACHEMOD_J…

Mycat环境搭建和管理及实现jsp通过tomcat连接mysql

一、什么是tomcat 官方网站&#xff1a;http://tomcat.apache.org/ Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。由于有了 Sun 的参与和支持…

Liunx下Tomcat中配置SSL协议(http转https)+域名配置SSL证书

问题描述 为什么http转https?什么情况下需要用到http转https?https优点!!!https缺点!!!废话不多说了上代码,阿里的产品为例(tomcat配置ssl). 准备材料:获取到证书点击上图的帮助可查看自带的配置文档个人感觉挺详细的 配置域名SSL证书对应上图进行选择配置就ok 接下来我们就配…

Tomcat通过自带的Cluster方式实现Session会话共享

一般来说,在多个tomcat集群业务中,session会话共享是必须的需求,不然前端nginx转发过来的请求不知道之前请求在哪台tomcat节点上&#xff0c;从而就找不到session以至于最终导致请求失败。要实现tomcat session共享有多种方案,今天介绍下使用tomcat自带的cluster方式&#xff0…

redhat 7.9 部署war包(二)之 环境安装 jdk,tomcat等

tomcat服务器环境搭建 redhat 7.9系统中搭建tomcat8.5.88服务器端在redhat中安装tomcat8一.传输文件到虚拟机中二.设置系统环境变量 JAVA_HOME三.启动tomcat8 部署war包 redhat 7.9系统中搭建tomcat8.5.88服务器端 本篇文章介绍&#xff0c;如何在redhat7.9环境下安装java web…

tomcat看源码

一.环境搭建 1.官网下载tomcat9 2.idea打开 新建pom文件 <!-- 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-inst…

centos 6.2 mysql和tomcat的配置_基于CentOS 6.8平台的Tomcat+MySQL+JDK环境搭建

部署环境 Server&#xff1a;CentOS 6.8 x86_64 Tomcat&#xff1a;9.0.0.M9 MySQL&#xff1a;5.7.14 JDK&#xff1a;8u102 部署准备 使用浏览器访问Apache Tomcat官网 http://tomcat.apache.org/ 下载目前最新9版本 9.0.0.M9版本tar.gz安装包 下载Apache Commons Daemon&…

Windows下配置Tomcat集群

为什么要用Tomcat集群 可以提高整体web服务器性能&#xff0c;将动态页面交给tomcat处理&#xff0c;将静态文件交给apache处理&#xff0c;可以大大提高服务器的静态文件处理性能。 可以实现web服务器的负载均衡&#xff0c;服务器可采用集群的方式来响应客户端请求。Apache的…

tomcat连接mysql及JDBC详解

一、Tomcat简介 1、Tomcat简介 Tomcat 是 Apache 软件基金会&#xff08;Apache Software Foundation&#xff09;的 Jakarta 项目中的一个核心项目&#xff0c;由 Apache、Sun 和其他一些公司及个人共同开发而成。由于有了 Sun 的参与和支持&#xff0c;最新的 Servlet 和JS…

tomcat配置url跳转_web和tomcat的区别

在Web2.0的浪潮中&#xff0c;各种页面技术和框架不断涌现&#xff0c;为服务器端的基础架构提出了更高的稳定性和可扩展性的要求。近年来&#xff0c;作为开源中间件的全球领导者&#xff0c;JBoss在J2EE应用服务器领域已成为发展最为迅速的应用服务器。在市场占有率和服务满意…

Windows下安装配置Tomcat

Windows下安装配置Tomcat 下载 到官网下载目标Tomcat版本&#xff1a;https://tomcat.apache.org/ 下载完成后&#xff0c;进入目标目录下 解压到安装目录 配置 配置环境变量&#xff1a; 变量名为&#xff1a;CATALINA_HOME 变量值为&#xff1a;D:\software\tapache-t…