第40天:JavaEE安全开发SpringBoot JWT身份鉴权与打包部署(JAR&WAR)

一、核心知识点总览

本节课聚焦SpringBoot开发的"身份安全+上线部署"两大核心场景,核心分两部分:

  1. JWT鉴权:理解JSON Web Token的原理,实现用户身份的加密传输与验证,解决传统Session的分布式问题;
  2. 打包部署:掌握SpringBoot项目两种部署格式(JAR/WAR)的实战步骤,明确两者差异与常见问题;
  3. 安全重点:JWT的密钥保护、签名验证,以及部署后的源码泄漏风险防御。

二、SpringBoot 身份鉴权:JWT技术

JWT(JSON Web Token)本质是"加密的用户身份凭证",无需服务端存储Session,只需通过Token本身验证身份(适合分布式系统)。可以类比为"带防伪标志的电子身份证"------Header是"证件类型",Payload是"用户信息",Signature是"防伪印章"。

2.1 JWT基础概念:三部分结构

JWT最终是一串以.​分隔的字符串,格式为Header.Payload.Signature​,三部分均通过Base64编码(注意:Base64是编码不是加密,可解码,安全靠Signature)。

部分 作用 示例(JSON格式)
Header 声明Token类型(typ)和签名算法(alg) ​json {"alg": "HS256", "typ": "JWT"} ​(HS256:HMAC-SHA256对称加密算法)
Payload 存储用户信息(自定义字段+标准声明) ​json {"userid": 1, "username": "admin", "iat": 1516239022} ​(iat:Token生成时间)
Signature 对Header+Payload的签名,防止篡改 算法:HMACSHA256(Base64Encode(Header) + "." + Base64Encode(Payload), 密钥)​

关键:Payload可解码查看,安全性靠Signature------若篡改Payload,未重新用密钥签名,服务端验证会失败。

2.2 JWT实战步骤(基于com.auth0:java-jwt​)

步骤1:引入JWT依赖(pom.xml)

使用auth0​的Java-JWT库(轻量、易用),指定版本3.4.0​:

复制代码
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.4.0</version>
</dependency>
步骤2:创建JWT Token(生成"电子身份证")

编写JwtController​,实现用户信息加密生成Token的接口(模拟用户登录成功后返回Token):

复制代码
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JwtController {
    // 密钥(核心!必须保密,生产环境用复杂密钥,如32位随机字符串)
    private static final String SECRET = "xiaodisec";

    /**
     * 生成JWT Token
     * @param id 用户ID(自定义参数)
     * @param user 用户名(自定义参数)
     * @param pass 密码(实际开发中不建议存密码,此处仅演示)
     * @return 生成的JWT字符串
     */
    @PostMapping("/jwtcreate")
    @ResponseBody
    public String createToken(
            @RequestParam Integer id,
            @RequestParam String user,
            @RequestParam String pass) {
        try {
            // 1. 指定签名算法(与Header一致,HS256对称算法)
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            // 2. 构建JWT Token
            String jwtToken = JWT.create()
                    // 自定义Payload字段(用户信息,可按需添加)
                    .withClaim("userid", id)
                    .withClaim("username", user)
                    .withClaim("password", pass) // 实际开发:禁止存明文密码!
                    // (可选)设置Token过期时间,如2小时:.withExpiresAt(new Date(System.currentTimeMillis() + 7200000))
                    // 3. 用密钥签名,生成最终Token
                    .sign(algorithm);
            System.out.println("生成的JWT:" + jwtToken);
            return jwtToken;
        } catch (Exception e) {
            e.printStackTrace();
            return "Token生成失败";
        }
    }
}
步骤3:解析JWT Token(验证"电子身份证")

添加解析接口,验证Token合法性(签名是否正确),并提取用户信息:

复制代码
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JwtController {
    // 复用之前的密钥(必须与生成Token时一致!)
    private static final String SECRET = "xiaodisec";

    // 省略createToken方法...

    /**
     * 解析并验证JWT Token
     * @param jwtdata 前端传入的JWT字符串
     * @return 验证结果(如用户信息或错误提示)
     */
    @PostMapping("/jwtcheck")
    @ResponseBody
    public String checkToken(@RequestParam String jwtdata) {
        try {
            // 1. 构建验证器(指定算法和密钥,与生成时一致)
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm).build();
            // 2. 验证Token(若签名错误/过期,会抛出异常)
            DecodedJWT decodedJWT = verifier.verify(jwtdata);
            // 3. 提取Payload中的用户信息
            Integer userId = decodedJWT.getClaim("userid").asInt();
            String username = decodedJWT.getClaim("username").asString();
            String password = decodedJWT.getClaim("password").asString();
            // 4. 返回验证结果(实际开发:可根据用户信息判断权限)
            String result = "验证成功!用户信息:ID=" + userId + ",用户名=" + username;
            System.out.println(result);
            return result;
        } catch (Exception e) {
            // Token无效(签名错误/过期/篡改)
            return "Token无效:" + e.getMessage();
        }
    }
}
步骤4:前端页面(模拟用户交互)

在resources/static​目录下创建index.html​,提供"生成Token"和"验证Token"的表单:

复制代码
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>JWT测试页面</title>
</head>
<body>
    <h2>1. 生成JWT Token</h2>
    <form action="/jwtcreate" method="post">
        用户ID:<input type="text" name="id" required><br>
        用户名:<input type="text" name="user" required><br>
        密码:<input type="text" name="pass" required><br>
        <input type="submit" value="生成Token">
    </form>

    <h2>2. 验证JWT Token</h2>
    <form action="/jwtcheck" method="post">
        输入Token:<input type="text" name="jwtdata" required style="width: 500px;"><br>
        <input type="submit" value="验证Token">
    </form>
</body>
</html>

测试流程:

  1. 访问http://localhost:8080/index.html,输入用户信息(如ID=1,用户=admin,密码=123456);
  2. 点击"生成Token",获取类似eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMzQ1NiIsInVzZXJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiJ9.q__DmCYaffqXmQweBgITek-NmhsSAhgwExNA3lQspQk的字符串;
  3. 将Token粘贴到"验证Token"表单,点击验证,显示"验证成功"。

2.3 JWT安全风险与防御

JWT的安全核心是"密钥保护"和"签名验证",常见风险及防御措施如下:

安全风险 表现形式 防御措施
密钥爆破 攻击者用工具暴力破解简单密钥(如xiaodisec​),篡改Token后重新签名 1. 使用强密钥(至少32位随机字符串,如a8f5d2b9c7e3f1a4b6c8d0e2f4a6b8c0​);2. 定期更换密钥
未验证签名 服务端未执行verifier.verify()​,直接解码Payload,攻击者可篡改用户信息 1. 强制验证签名(必须调用verify()​方法);2. 捕获签名异常,直接拒绝无效Token
Token无过期时间 Token永久有效,泄露后攻击者可长期使用 1. 生成Token时添加过期时间(withExpiresAt(new Date(System.currentTimeMillis() + 3600000))​,1小时过期);2. 实现Token刷新机制
Payload存敏感信息 直接存储明文密码、Token等,Base64解码后可直接查看 1. 禁止存敏感信息(如密码,可存用户ID、角色);2. 敏感信息需额外加密(如AES)

三、SpringBoot 打包部署:JAR&WAR

SpringBoot项目有两种部署格式,核心差异是"是否依赖外部Tomcat"------JAR内置Tomcat,直接运行;WAR需部署到外部Tomcat。

3.1 JAR包部署(推荐:快速、轻量)

JAR是SpringBoot默认打包格式,内置嵌入式Tomcat,无需额外配置服务器,适合单机/小型项目。

步骤1:配置pom.xml(确保打包类型为JAR)

默认即为JAR,无需额外修改,若需指定主类(防止打包后找不到入口),可添加:

复制代码
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <!-- 指定SpringBoot启动类(替换为你的启动类全路径) -->
                <mainClass>com.example.testjwt.TestJwtApplication</mainClass>
                <!-- 关键:设为false,否则打包会跳过主类(常见报错点!) -->
                <skip>false</skip>
            </configuration>
        </plugin>
    </plugins>
</build>
步骤2:执行Maven打包命令
  1. 方式1:IDE中操作(如IDEA)

    右侧"Maven"→ 项目名 → Lifecycle → 双击clean​(清理旧包)→ 双击package​(生成新包)。

  2. 方式2:命令行操作

    进入项目根目录(含pom.xml的目录),执行:

    复制代码
    mvn clean package
步骤3:运行JAR包

打包完成后,包位于target​目录下(如testjwt-0.0.1-SNAPSHOT.jar​),执行命令运行:

复制代码
# 格式:java -jar 包名.jar
java -jar testjwt-0.0.1-SNAPSHOT.jar

3.2 WAR包部署(需外部Tomcat:适合企业级部署)

WAR格式需排除SpringBoot内置Tomcat,部署到外部Tomcat(如Tomcat 9),适合多项目共享服务器的场景。

步骤1:修改pom.xml(设置为WAR+排除内置Tomcat)
复制代码
<!-- 1. 打包类型改为WAR -->
<packaging>war</packaging>

<dependencies>
    <!-- 2. 排除内置Tomcat(避免与外部Tomcat冲突) -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-tomcat</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- 3. 添加Servlet API依赖(外部Tomcat需要) -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope> <!-- 仅编译时生效,外部Tomcat提供 -->
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <mainClass>com.example.testjwt.TestJwtApplication</mainClass>
                <skip>false</skip>
            </configuration>
        </plugin>
    </plugins>
    <!-- 可选:指定WAR包名(默认是项目名+版本,可简化) -->
    <finalName>testjwt</finalName>
</build>
步骤2:修改启动类(继承SpringBootServletInitializer​)

让SpringBoot适配外部Tomcat的Servlet容器:

复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
// 关键:继承SpringBootServletInitializer,重写configure方法
public class TestJwtApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(TestJwtApplication.class, args);
    }

    // 重写configure,指定启动类
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(TestJwtApplication.class);
    }
}
步骤3:打包并部署到外部Tomcat
  1. 执行Maven打包:同JAR包(mvn clean package),生成的WAR包在target目录下(如testjwt.war);
  2. 部署到Tomcat:
    将WAR包复制到Tomcat的webapps目录下(如apache-tomcat-9.0.27/webapps);
  3. 启动Tomcat:
    运行Tomcat的bin/startup.bat(Windows)或bin/startup.sh(Linux);
  4. 访问:
    路径格式为http://服务器IP:Tomcat端口/WAR包名/index.html(如http://localhost:8080/testjwt/index.html)。

3.3 部署后安全:源码泄漏风险

SpringBoot打包后的JAR/WAR是压缩文件,若被攻击者获取,可通过工具反编译获取源码,需注意:

  1. 反编译方式:

    • 直接用IDEA打开JAR/WAR包,IDEA会自动反编译class文件,显示源码;
    • 用工具(如JD-GUI)打开class文件,查看源码。
  2. 防御措施:

    • 生产环境避免将JAR/WAR包暴露在可下载路径(如Web根目录);
    • 使用代码混淆工具(如ProGuard),降低反编译后源码的可读性;
    • 敏感配置(如JWT密钥、数据库密码)不硬编码,通过环境变量或配置中心(如Nacos)注入。

四、核心总结

模块 核心要点
JWT鉴权 1. 三部分结构:Header(算法)、Payload(用户信息)、Signature(签名);2. 安全核心是密钥+签名验证;3. 必须加Token过期时间
JAR部署 内置Tomcat,mvn clean package​打包,java -jar​运行,适合快速部署
WAR部署 需排除内置Tomcat、继承SpringBootServletInitializer​,部署到外部Tomcat,适合企业级场景
安全防御 1. JWT用强密钥+过期时间;2. 禁止Payload存敏感信息;3. 保护JAR/WAR包,避免源码泄漏
相关推荐
测试人社区-千羽3 小时前
生物识别系统的测试安全性与漏洞防护实践
运维·人工智能·opencv·安全·数据挖掘·自动化·边缘计算
哈哈老师啊3 小时前
Springboot简单二手车网站qs5ed(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
JIngJaneIL3 小时前
基于Java+ vue图书管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
网络研究院3 小时前
2026年智能体人工智能的激增引发新的网络安全风险
网络·人工智能·安全·web安全·ai
VX:Fegn08954 小时前
计算机毕业设计|基于springboot + vue考勤管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
一 乐4 小时前
幼儿园管理|基于springboot + vue幼儿园管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端
JIngJaneIL4 小时前
基于Java + vue校园论坛系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
期待のcode4 小时前
Springboot多数据源配置
java·数据库·spring boot·后端·mybatis