12306项目学习笔记(框架篇bizs)

UserAutoConfiguration

UserAutoConfiguration,用于注册一个全局的用户信息传输过滤器 UserTransmitFilter。该类只用于web应用(@ConditionalOnWebApplication

  • UserTransmitFilter: 这是一个 Servlet 过滤器,用于从 HTTP 请求中提取用户信息并存储到 UserContext 中。
  • doFilter 方法:
    • 从请求头中获取用户 ID、用户名、真实姓名和 Token。
    • 如果获取到用户 ID,则构建 UserInfoDTO 对象并存入 UserContext
    • 最后,调用 filterChain.doFilter 继续处理请求,确保在请求处理完成后清理用户信息。

UserContext

它使用了 ThreadLocal 来存储当前线程的用户信息,以便在整个请求处理过程中能够方便地访问用户相关的数据。

Theadlocal是什么?有哪些使用场景?底层实现是什么?-CSDN博客

private static final ThreadLocal<UserInfoDTO> USER_THREAD_LOCAL = new TransmittableThreadLocal<>();
  • ThreadLocal<UserInfoDTO>ThreadLocal 是 Java 提供的一个类,用于在每个线程中存储独立的变量。每个线程都有自己的 UserInfoDTO 实例,避免了线程间的干扰。
  • TransmittableThreadLocal: 这是 ThreadLocal 的一个扩展,支持在异步操作中传递值。它可以在不同的线程之间传递用户信息,适用于高并发场景中的异步请求处理。
public class AsyncTaskExecutor {
    private static final ThreadLocal<UserInfo> USER_INFO_THREAD_LOCAL = new TransmittableThreadLocal<>();

    public static void submitTask(Runnable task) {
        // 在提交任务之前,先设置用户信息
        UserInfo userInfo = new UserInfo("user123", "John Doe");
        USER_INFO_THREAD_LOCAL.set(userInfo);

        // 提交任务
        new Thread(task).start();
    }

    public static void processTask() {
        // 在处理任务时,可以获取到用户信息
        UserInfo userInfo = USER_INFO_THREAD_LOCAL.get();
        System.out.println("Processing task for user: " + userInfo.getUserId() + " (" + userInfo.getUsername() + ")");

        // 模拟处理任务
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我们使用了 TransmittableThreadLocal 来存储用户信息。当我们提交一个异步任务时,会先设置用户信息,然后启动一个新线程来执行任务。

AsyncTaskExecutor.submitTask(() -> {
    AsyncTaskExecutor.processTask();
});

在任务的处理方法 processTask() 中,我们可以通过 USER_INFO_THREAD_LOCAL.get() 获取到之前设置的用户信息。这是因为 TransmittableThreadLocal 会自动将用户信息传递到新的线程中。

这个类使用 Optional 来避免空指针异常,如果用户信息为空,则返回 null

UserTransmitFilter

UserTransmitFilter 是一个实现了 Filter 接口的过滤器,负责在每个 HTTP 请求中提取用户信息并将其存储到用户上下文中。

UserAutoConfiguration中我们注册了UserTransmitFilter,所有的http请求都会经过这个过滤器,优先级为100。

在 doFilter 方法中,过滤器首先从请求中提取用户信息:

HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

ServletRequest 类型的 servletRequest 转换为 HttpServletRequest 类型。HttpServletRequest 是一个更具体的接口,提供了处理 HTTP 请求的特定方法,比如获取请求头、请求参数等。

UserContext.setUser(userInfoDTO);
        }
        try {
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            UserContext.removeUser();
        }

 UserContext.setUser(userInfoDTO) 将用户信息存储到上下文中后,后续的过滤器以及其他处理逻辑(如控制器、服务层等)都可以直接从 UserContext 中获取用户信息

在 Spring Web 应用中,filterChain.doFilter(servletRequest, servletResponse) 是用来将请求传递给下一个过滤器或目标资源(如控制器)的。如果当前过滤器是过滤器链中的最后一个过滤器将直接将请求传递给目标资源(如控制器)

控制器的响应返回后,LastFilter 和 FirstFilter 的 doFilter 方法继续执行 finally 块中的逻辑,比如这里的UserContext.removeUser();即使的remove防止内存泄漏。

JWTUtil

JWTUtil 是一个用于生成和解析 JSON Web Token (JWT) 的工具类。在现代 Web 应用中,JWT 常用于用户身份验证和授权。

@Slf4j
public final class JWTUtil {
    private static final long EXPIRATION = 86400L; // Token 过期时间(单位:秒)
    public static final String TOKEN_PREFIX = "Bearer "; // Token 前缀
    public static final String ISS = "index12306"; // Token 发行者
    public static final String SECRET = "SecretKey039245678901232039487623456783092349288901402967890140939827"; // 签名密钥
}
  • EXPIRATION:定义了 Token 的有效期(86400 秒,即 24 小时)。
  • TOKEN_PREFIX:用于标识 Token 的前缀,通常在 HTTP 头中使用。
  • ISS:定义了 Token 的发行者,通常是应用的标识。
  • SECRET:用于签名和验证 Token 的密钥,确保 Token 的安全性。

SECRET 通常是随机生成的字符串,可以使用加密库(如 Java 的 SecureRandom)来生成一个强随机密钥。

import java.security.SecureRandom;
import java.util.Base64;

public class SecretGenerator {
    public static String generateSecret() {
        byte[] randomBytes = new byte[32]; // 256 bits
        SecureRandom secureRandom = new SecureRandom();
        secureRandom.nextBytes(randomBytes);
        return Base64.getEncoder().encodeToString(randomBytes);
    }
}

SECRET 应该足够长(至少 256 位)并且复杂,以防止暴力破解。通常,使用 Base64 编码的随机字节串是一个好的选择。

       String jwtToken = Jwts.builder()
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .setIssuedAt(new Date())
                .setIssuer(ISS)
                .setSubject(JSON.toJSONString(customerUserMap))
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION * 1000))
                .compact();
        return TOKEN_PREFIX + jwtToken;

指定签名算法为 HMAC SHA-512(HS512),并使用 SECRET 作为签名密钥。这个密钥用于生成和验证 JWT 的有效性。

设置 JWT 的签发时间为当前时间。

设置 JWT 的发行者(iss 声明),通常是应用的标识,这里使用常量 ISS

设置 JWT 的主题(sub 声明),这里将用户信息的 map 转换为 JSON 字符串,并作为主题存储在 JWT 中。

设置 JWT 的过期时间,当前时间加上 EXPIRATION(单位为秒),表示 Token 的有效期。

构建并返回 JWT 字符串,compact() 方法将所有设置的属性组合成一个 JWT。

  • 18
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值