⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7383017171180568630 「云原生melo荣」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

使用JWT进行用户认证和授权,而Session在一定程度上起到了辅助作用。让我们详细讨论JWT和Session在这种结合模式中的各自作用以及为什么需要Session。

JWT的作用

  • 用户认证: JWT包含了用户的身份信息和权限信息,客户端每次请求时将JWT发送给服务器,服务器通过验证JWT来确认用户身份。
  • 无状态性: JWT不需要在服务器端存储用户会话信息,因此服务器可以是无状态的,便于扩展和负载均衡。

Session的作用

  • 附加的安全层: 即使JWT是无状态的,但在某些应用场景中,仅依赖JWT可能存在一些安全问题,例如Token的泄露或滥用。Session可以作为一个额外的安全层,确保Token即使有效,也必须在服务器的Session管理器中存在对应的会话。
  • 管理Token的生命周期: 通过Session,可以更方便地管理Token的生命周期,例如强制用户重新登录、手动注销Token等操作。
  • 控制“记住我”功能: 如果用户选择了“记住我”选项,Session可以记录这个状态,并在JWT过期后,通过Session来决定是否允许继续使用旧的Token。

为什么需要创建Session

尽管JWT可以在无状态环境中使用,但Session的引入带来了以下好处:

  • 防止Token滥用: 通过在服务器端验证Session,可以确保即使Token有效,也必须是经过服务器端认证的,从而防止Token被恶意使用。
  • 支持用户主动注销: 当用户选择注销时,可以直接删除服务器端的Session记录,确保Token即使没有过期,也无法再被使用。
  • 提供更精细的控制: 通过Session,可以实现更精细的权限控制和用户状态管理,例如强制下线、会话过期时间控制等。
  • 状态追踪: 在某些场景下,追踪用户状态是必要的,例如监控用户的活跃度、登录历史等,这些信息可以通过Session进行管理。

结合JWT和Session的优势

结合使用JWT和Session,可以同时利用两者的优点,实现安全性和扩展性的平衡:

  • 无状态认证: JWT可以实现无状态认证,便于系统的水平扩展和负载均衡。
  • 状态管理和安全性: Session可以提供额外的状态管理和安全性,确保Token的使用更加安全可靠。

代码示例

以下是一个简化的代码示例,展示了如何在用户登录时创建JWT和Session:

public LoginResponse login(String username, String password) throws AuthException {
// 验证用户名和密码
User user = userService.authenticate(username, password);
if (user == null) {
throw new AuthException("Invalid username or password");
}

// 生成JWT Token
String token = createJwt(user.getId(), user.getRoles());

// 创建会话
sessionManagerApi.createSession(token, user);

// 返回Token
return new LoginResponse(token);
}

public void createSession(String token, User user) {
LoginUser loginUser = new LoginUser();
loginUser.setToken(token);
loginUser.setUserId(user.getId());
loginUser.setRoles(user.getRoles());

sessionManagerApi.saveSession(token, loginUser);
}

在请求验证时,首先验证JWT的有效性,然后检查Session中是否存在对应的会话:

@Override
public DefaultJwtPayload validateToken(String token) throws AuthException {
try {
// 1. 先校验jwt token本身是否有问题
JwtContext.me().validateTokenWithException(token);

// 2. 获取jwt的payload
DefaultJwtPayload defaultPayload = JwtContext.me().getDefaultPayload(token);

// 3. 如果是7天免登陆,则不校验session过期
if (defaultPayload.getRememberMe()) {
return defaultPayload;
}

// 4. 判断session里是否有这个token
LoginUser session = sessionManagerApi.getSession(token);
if (session == null) {
throw new AuthException(AUTH_EXPIRED_ERROR);
}

return defaultPayload;
} catch (JwtException jwtException) {
if (JwtExceptionEnum.JWT_EXPIRED_ERROR.getErrorCode().equals(jwtException.getErrorCode())) {
throw new AuthException(AUTH_EXPIRED_ERROR);
} else {
throw new AuthException(TOKEN_PARSE_ERROR);
}
} catch (io.jsonwebtoken.JwtException jwtSelfException) {
throw new AuthException(TOKEN_PARSE_ERROR);
}
}

总结

在这个场景中,JWT用于无状态的用户认证,提供便捷和扩展性;Session作为辅助,提供额外的安全性和状态管理。通过这种结合,可以充分利用两者的优点,确保系统既具备高扩展性,又能提供细致的安全控制。

文章目录
  1. 1. JWT的作用
  2. 2. Session的作用
  3. 3. 为什么需要创建Session
  4. 4. 结合JWT和Session的优势
  5. 5. 代码示例
  6. 6. 总结