
040-安全开发-JavaEE应用&SpringBoot框架&JWT身份鉴权&打包部署JAR&WAR
目录
知识点与演示案例:
1、JavaEE-SpringBoot-身份鉴权-JWT技术
2、JavaEE-SpringBoot-打包部署-JAR&WAR
演示案例:
➢SpringBoot-身份鉴权-JWT技术
➢SpringBoot-打包部署-JAR&WAR

浏览器与服务器基于 JWT 的认证流程:
-
用户登录请求
- 浏览器发送
POST /users/login请求到服务器,包含username和password(这是身份认证的起点,用户需提供凭证)。
- 浏览器发送
-
服务器生成 JWT
- 服务器验证用户名和密码(核心步骤,验证失败则拒绝登录)。
- 若验证成功,使用密钥(Secret) 生成 JWT(JSON Web Token)(密钥是安全性的核心,必须妥善保管)。
- JWT 包含用户信息(如用户ID、角色等)和有效期(有效期用于控制令牌的使用时长,降低被盗用风险)。
-
返回 JWT 给浏览器
- 服务器将生成的 JWT 通过 HTTP 响应返回给浏览器(通常放在响应体或
Set-Cookie头中,不同存储方式有不同的安全考量,如Cookie可配置HttpOnly、Secure属性防XSS)。
- 服务器将生成的 JWT 通过 HTTP 响应返回给浏览器(通常放在响应体或
-
浏览器发送 JWT 后续请求
- 浏览器在后续请求的
Authorization请求头中添加 JWT,格式为:(这种方式是行业通用规范,便于服务器统一解析)Authorization: Bearer <JWT>
- 浏览器在后续请求的
-
服务器验证 JWT
- 服务器用相同的密钥验证 JWT 的签名,确保未被篡改(签名验证是防止令牌被伪造的关键)。
- 从 JWT 的
Payload中直接提取用户信息(无需查询数据库,提升效率,但依赖令牌本身的安全性)。
-
返回响应
- 服务器根据用户信息处理请求,将结果返回给浏览器。
关键点总结:
- 无状态认证:服务器无需保存会话状态,JWT 自包含用户信息(减少服务器存储压力,但令牌一旦发出无法主动撤销,需依赖有效期)。
- 安全性:
- 密钥(Secret)用于签名,防止 JWT 被篡改(密钥泄露会导致令牌可伪造,是最高风险点)。
- 全程需使用 HTTPS 防止 JWT 被窃取(HTTP 传输易被中间人拦截令牌)。
- 效率:
- 验证 JWT 签名后可直接读取用户信息,减少数据库查询(提升接口响应速度,但需平衡令牌大小与传输效率)。
⚠️ 注意:JWT 的
Payload仅经过 Base64 编码(非加密),切勿存放敏感信息(如密码)(Base64 可直接解码,敏感信息会暴露)。
SpringBoot-身份鉴权-JWT技术
JWT(JSON Web Token)是由服务端用加密算法对信息签名来保证其完整性和不可伪造;
Token里可以包含所有必要信息,这样服务端就无需保存任何关于用户或会话的信息;
JWT用于身份认证、会话维持等。由三部分组成:header、payload与signature。
JWT的组成
Header、Payload 和 Signature 是 JSON Web Token(JWT)的三个主要组成部分。
-
Header(头部):
JWT 的头部通常包含两部分信息:声明类型(typ)和使用的签名算法(alg)。这些信息以 JSON 格式存在,然后进行 Base64 编码,形成 JWT 的第一个部分。头部用于描述关于该 JWT 的元数据信息。{"alg": "HS256", // 签名算法(如HMAC SHA-256)"typ": "JWT" // 令牌类型}(算法选择影响安全性,HS256是对称加密,需双方共享密钥;RS256是非对称加密,用私钥签名、公钥验证,更适合分布式系统)
-
Payload(负载):
JWT 的负载包含有关 JWT 主题(subject)及其它声明的信息。与头部一样,负载也是以 JSON 格式存在,然后进行 Base64 编码,形成 JWT 的第二个部分。{"sub": "1234567890", // 主题(通常是用户ID)"name": "John Doe", // 自定义声明(用户名)"iat": 1516239022 // 签发时间(Unix时间戳)}(标准声明包括iss(签发者)、exp(过期时间)、sub(主题)等,自定义声明需避免敏感信息)
-
Signature(签名):
JWT 的签名是由头部、负载以及一个密钥生成的,用于验证 JWT 的真实性和完整性。签名是由指定的签名算法对经过 Base64 编码的头部和负载组合而成的字符串进行签名生成的。例如,使用 HMAC SHA-256 算法生成签名:
HMACSHA256(base64UrlEncode(header) + "." + // 编码后的头部base64UrlEncode(payload), // 编码后的负载secret // 服务器密钥)(签名是JWT的安全核心,若签名验证失败,令牌会被视为无效)
最终,JWT 是由这三个部分组成的字符串,形如 header.payload.signature。JWT 通常用于在网络上安全地传输信息,例如在身份验证过程中传递令牌。
实现步骤
1、创建项目引入依赖


<dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> <!-- JWT操作的核心依赖,提供生成、解析令牌的工具类 --></dependency>
2、创建JWT并配置JWT
对应目录下创建JwtController.java
package cn.xiaodi.testjwt.demos.web;
import com.auth0.jwt.JWT;import com.auth0.jwt.algorithms.Algorithm;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.ResponseBody;
@Controllerpublic class JwtController {
// 模拟用户的JWT身份创建,数据的JWT加密 @PostMapping("/jwtcreate") // 处理POST请求,路径为/jwtcreate @ResponseBody // 直接返回字符串,而非视图 public static String create(Integer id, String user, String pass) { // 创建JWT令牌 String jwttoken = JWT.create() // 设置创建的Header部分(可省略,默认使用算法配置) //.withHeader()
// 设置创建的Payload部分(自定义声明,存储用户信息) .withClaim("userid", id) // 用户ID .withClaim("username", user) // 用户名 .withClaim("password", pass) // 注意:实际开发中禁止存储密码!此处仅为演示
// 设置时效(JWT过期时间,如:.withExpiresAt(new Date(System.currentTimeMillis() + 3600000)) 表示1小时后过期) //.withExpiresAt()
// 创建设置的Signature部分,指定算法(HMAC256)和密钥(xiaodisec) .sign(Algorithm.HMAC256("xiaodisec")); // 密钥硬编码存在安全风险,实际需用配置文件存储
// 打印创建好的jwt System.out.println(jwttoken); return jwttoken; }
}3、解析JWT
// 模拟JWT身份的检测,JWT数据解密@PostMapping("/jwtcheck") // 处理POST请求,路径为/jwtcheck@ResponseBodypublic static String jwtcheck(String jwtdata) { // 构建JWT解密验证器:指定算法(与生成时一致)和密钥 JWTVerifier jwt = JWT.require(Algorithm.HMAC256("xiaodisec")).build();
// 解密并验证JWT:若签名无效或过期,会抛出异常 DecodedJWT verify = jwt.verify(jwtdata);
// 提取Payload部分的用户信息 Integer userid = verify.getClaim("userid").asInt(); String username = verify.getClaim("username").asString(); String password = verify.getClaim("password").asString(); // 演示用,实际应避免存储密码
System.out.println(userid + username + password); return "admin page"; // 验证通过后返回的资源
// 如果需要根据解密的数据执行不同的逻辑,可以使用以下代码进行判断 // if (username.equals("admin")) { // return "admin"; // } else { // return "gay?"; // }
// 提取Header部分 // verify.getHeader(); // 提取Sign签名部分 // verify.getSignature();}4、配置前端提交数据访问客户端页面
- 在resources→static→index.html创建如下的前端页面
<html><body> <h1>hello word!!!</h1> <p>this is an HTML page</p>
<!-- Form for creating JWT:用户输入信息生成JWT --> <form action="../jwtcreate" method="post"> id:<input type="text" name="id"><br> <!-- 对应后端create方法的id参数 --> user:<input type="text" name="user"><br> <!-- 对应username参数 --> pass:<input type="text" name="pass"><br> <!-- 对应password参数 --> <input type="submit" value="create"> <!-- 提交按钮,触发/jwtcreate请求 --> </form>
<!-- Form for checking JWT:输入JWT进行验证 --> <form action="../jwtcheck" method="post"> jwtdata:<input type="text" name="jwtdata"><br> <!-- 输入生成的JWT字符串 --> <input type="submit" value="check"> <!-- 提交按钮,触发/jwtcheck请求 --> </form></body></html>
-
对应输入id,用户名,密码,点击创建得到eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMzQ1NiIsInVzZXJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9.q__DmCYaffqXmQweBgITek-NmhsSAhgwExNA3lQspQk
-
在官网进行解密(官网提供JWT编码/解码工具,可用于调试,但敏感令牌需避免在此类工具中暴露)
-
在页面对应输入对应jwtdata,进行解密
-
跳转至解密成功页面,回显admin page






安全问题与网安风险

-
未使用密钥加密(或签名验证失效)
只有JWT编码,在JWT官网修改用户参数信息后重新编码,由于缺少签名验证,服务器可能误判为有效令牌。- 正常情况下,服务器会报错“令牌无效”(因签名不匹配)。


-
密钥泄露风险
若攻击者获取密钥,可修改Payload后用密钥重新签名,生成“合法”令牌。- 示例:输入密钥,修改用户信息后重新生成令牌,可成功登录。



更多网安风险补充:
-
密钥爆破
若密钥强度低(如短字符串、常见密码),攻击者可通过暴力破解工具尝试猜测密钥,进而伪造令牌。

(防御:使用长随机字符串作为密钥,如32位以上随机字符,避免硬编码在代码中,通过环境变量或加密配置文件存储) -
未验证签名
部分开发可能因疏忽跳过签名验证步骤(如直接解析Payload而不验证签名),导致攻击者可随意篡改令牌内容。

(防御:严格执行签名验证流程,任何情况下不跳过验证) -
算法协商漏洞
若服务器支持动态选择签名算法(如允许客户端指定alg: none),攻击者可伪造无签名的令牌,服务器可能接受为有效。
(防御:固定签名算法,不允许客户端指定,如强制使用HS256或RS256) -
过期时间设置不当
若JWT过期时间过长(如永久有效),令牌被盗后攻击者可长期滥用;若过短,会频繁要求用户重新登录,影响体验。
(防御:根据业务场景设置合理过期时间,如1小时,同时实现令牌刷新机制)
SpringBoot-打包部署-JAR&WAR
参考:https://mp.weixin.qq.com/s/HyqVt7EMFcuKXfiejtfleg
SpringBoot项目打包在linux服务器中运行:
JAR类型项目
jar类型项目使用SpringBoot打包插件打包时,会在打成的jar中内置tomcat的jar。
所以使用jdk直接运行jar即可,jar项目中功能将代码放到其内置的tomcat中运行。
-
Jar打包步骤
报错解决:https://blog.csdn.net/wobenqingfeng/article/details/129914639
https://blog.csdn.net/Mrzhuangr/article/details/124731024
将
<skip>true</skip>修改为<skip>false</skip>即可(skip设为false表示启用打包插件)-
<configuration>: Maven 插件配置的根元素,包含具体配置内容。 -
<mainClass>: 指定 Java 应用程序的主类(入口点),此处为com.example.testjwt.TestJwtApplication。 -
<skip>: 控制插件是否跳过执行,true为跳过,false为执行(打包时需设为false)。
- 执行
maven-clean-package命令(清理并打包,生成jar文件)。 - 运行命令
java -jar xxxxxx.jar(通过JDK直接启动内置Tomcat,无需额外部署容器)。
-

会报错:

不会报错(可以发现多了一个文件):



WAR类型项目
在打包时需要将内置的tomcat插件排除,配置servlet的依赖和修改pom.xml,
然后将war文件放到tomcat安装目录webapps下,启动运行tomcat自动解析即可。
-
pom.xml配置:
修改打包类型为war:<packaging>war</packaging>
-
启动类配置:
@SpringBootApplication// @SpringBootApplication 注解标识Spring Boot应用主类,自动扫描同包/子包组件public class TestJwtApplication extends SpringBootServletInitializer { // 继承SpringBootServletInitializer以支持WAR部署
public static void main(String[] args) { // 启动Spring Boot应用(JAR部署时使用) SpringApplication.run(TestJwtApplication.class, args); }
@Override protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { // 配置应用构建器(WAR部署时Tomcat会调用此方法初始化应用) return builder.sources(TestJwtApplication.class); }}
-
执行
maven-clean-package命令(生成war文件)。
-
将war文件放置到tomcat的
D:\....\apache-tomcat-9.0.27\webapps文件夹后启动
运行该文件夹下的tomcat的startup.bat启动程序(Windows)或startup.sh(Linux)

遇到环境变量问题参考https://zhidao.baidu.com/question/1682233609979465627.html



打包部署的网安补充:
- JAR/WAR文件安全:打包时需排除敏感文件(如配置文件中的密钥、数据库密码),避免随包泄露;可通过Maven插件过滤敏感文件。
- 内置Tomcat漏洞:JAR包内置的Tomcat若版本过低,可能存在已知漏洞(如远程代码执行),需定期升级SpringBoot版本以更新内置组件。
- 部署权限控制:服务器上的JAR/WAR文件及运行目录应限制权限(如仅管理员可读写),避免被恶意篡改;运行用户应使用低权限账号(非root),降低被攻击后的影响范围。
JAVAEE源码架构安全
无源码下载泄漏风险
- 无下载路径,运行的程序是一个压缩包,不能通过访问下载路径去下载源码(相比PHP等脚本语言,Java编译后的class文件不易直接获取源码,但仍需防范压缩包泄露)


源码泄漏也需反编译
- 如果得到打包好的源码,将打包的源码进行解压(攻击者若获取JAR/WAR包,可通过反编译工具还原源码)

直接使用idea打开文件夹,即可实现自动反编译,看到源码(反编译后的代码可能存在变量名混淆,但核心逻辑可被还原,需通过代码混淆工具增强保护)


难点总结
-
JWT密钥管理
- 难点:密钥需保证高强度且不泄露,同时在分布式系统中安全同步(如多服务器共享密钥)。
- 解决:使用环境变量或加密配置中心存储密钥,避免硬编码;非对称加密(如RS256)可避免密钥共享问题。
-
JWT过期与刷新机制
- 难点:平衡安全性(短有效期)与用户体验(减少登录频率)。
- 解决:实现“访问令牌+刷新令牌”机制,访问令牌短期有效(如1小时),刷新令牌长期有效(如7天),过期后用刷新令牌获取新访问令牌。
-
JWT签名验证的严格性
- 难点:开发中易因疏忽跳过签名验证或使用不安全的算法(如none)。
- 解决:封装JWT工具类,强制验证签名和过期时间,固定签名算法,禁止动态协商。
-
JAR与WAR部署的选择与配置
- 难点:内置Tomcat与外部Tomcat的配置差异(如端口、上下文路径),以及依赖冲突问题。
- 解决:JAR适合快速部署和微服务场景,需注意内置组件版本;WAR适合传统容器部署,需正确排除内置Tomcat并匹配外部容器版本。
-
源码保护
- 难点:JAR/WAR包易被反编译,导致核心逻辑或敏感信息泄露。
- 解决:使用代码混淆工具(如ProGuard),移除调试信息,敏感配置不随包存储,通过环境变量注入。