个人博客网站搭建day2-Spring Boot 3 + JWT + Redis 实现后台权限拦截与单点登录(漫画解析)

📅 发布时间:2026/7/12 21:01:56 👁️ 浏览次数:
个人博客网站搭建day2-Spring Boot 3 + JWT + Redis 实现后台权限拦截与单点登录(漫画解析)
深入剖析 Spring Boot 3 JWT Redis 实现后台权限拦截与单点登录前言在博客网站开发中安全且高效的权限认证体系是不可或缺的基石。传统的 Session 认证在分布式环境下存在扩展性问题而纯粹的 JWT 无状态认证又难以实现“强制踢人下线”或“单点登录”等复杂业务需求。基于以上的问题本人采用springboot3springmvcjwtRedis进行构建这一套“混合式”后台权限管理与单点登录SSO校验机制Spring Security配置讲解Spring Security一、 架构设计思路为了解决上述痛点我们采用JWT Redis 双重校验的混合架构。在这套架构中JWT负责携带用户基本信息如 userId, username并提供防篡改的签名验证。Redis作为有状态的辅助存储记录当前有效的 Token用于控制 Token 的生命周期和唯一性。Spring MVC 拦截器 (Interceptor)作为前端请求进入 Controller 之前的统一关卡负责执行上述校验逻辑。二、 核心拦截器实现JwtInterceptorJwtInterceptor是整个权限校验体系的核心枢纽实现了HandlerInterceptor接口。它不仅负责静态的 Token 解析还负责与 Redis 交互进行动态状态比对。2.1 拦截器完整代码packagecom.xuan.common.interceptor;importcom.alibaba.fastjson2.JSON;importcom.nimbusds.jwt.JWTClaimsSet;importcom.xuan.common.domain.Result;importcom.xuan.common.enums.ErrorCode;importcom.xuan.common.utils.JwtUtils;importcom.xuan.common.constant.RedisConstant;importjakarta.servlet.http.HttpServletRequest;importjakarta.servlet.http.HttpServletResponse;importlombok.RequiredArgsConstructor;importlombok.extern.slf4j.Slf4j;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.stereotype.Component;importorg.springframework.web.servlet.HandlerInterceptor;Slf4jComponentRequiredArgsConstructorpublicclassJwtInterceptorimplementsHandlerInterceptor{privatefinalJwtUtilsjwtUtils;privatefinalStringRedisTemplatestringRedisTemplate;OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{// 1. 放行 OPTIONS 请求if(OPTIONS.equalsIgnoreCase(request.getMethod())){returntrue;}// 2. 获取并校验 Token 基础信息Stringtokenrequest.getHeader(jwtUtils.getHeader());if(tokennull||token.isEmpty()){writeErrorResponse(response,ErrorCode.UNAUTHORIZED);returnfalse;}StringtokenPrefixjwtUtils.getTokenPrefix();if(token.startsWith(tokenPrefix)){tokentoken.substring(tokenPrefix.length()).trim();}try{// 3. 解析 TokenJWTClaimsSetclaimsSetjwtUtils.getAllClaimsFromToken(token);StringusernameclaimsSet.getSubject();// 4. Redis 双重比对StringredisKeyRedisConstant.TOKEN_KEY_PREFIXusername;StringstoredTokenstringRedisTemplate.opsForValue().get(redisKey);if(storedTokennull){writeErrorResponse(response,ErrorCode.TOKEN_EXPIRED);returnfalse;}if(!storedToken.equals(token)){writeErrorResponse(response,ErrorCode.TOKEN_REPLACED);returnfalse;}// 5. 上下文透传request.setAttribute(userClaims,claimsSet);request.setAttribute(username,username);request.setAttribute(userId,claimsSet.getClaim(userId));returntrue;}catch(Exceptione){log.error(Token 验证失败: {},e.getMessage());writeErrorResponse(response,ErrorCode.TOKEN_INVALID);returnfalse;}}privatevoidwriteErrorResponse(HttpServletResponseresponse,ErrorCodeerrorCode)throwsException{response.setContentType(application/json;charsetUTF-8);response.setStatus(HttpServletResponse.SC_OK);Result?resultResult.error(errorCode);response.getWriter().write(JSON.toJSONString(result));}}2.2 核心逻辑剖析1. 放行 CORS 预检请求在前后端分离架构中浏览器会针对复杂请求发送OPTIONS预检请求。预检请求本身不携带自定义 Header如 Token因此拦截器必须优先将其放行。这保证了跨域请求的顺利握手。2. Token 提取与基础校验拦截器从请求头中获取 Token判断为空时直接返回未授权错误。为了兼容 OAuth2 等标准协议代码灵活处理了 Token 的前缀如Bearer通过截取前缀获取真实的 Token 字符串。3. JWT 解析与 Redis 双重比对核心单点登录逻辑通过JwtUtils解析获取到username后程序会去 Redis 中查找对应的存储记录。此处设计了两个维度的拦截Token 失效拦截如果 Redis 中不存在该 Token值为 null说明用户可能已主动登出或 Token 自然过期被 Redis 清理此时返回TOKEN_EXPIRED错误。顶号/单点登录拦截如果 Redis 中存储的 Token 与当前请求携带的不一致说明该账号在其他设备或浏览器重新登录了覆盖了 Redis 中的旧值此时返回TOKEN_REPLACED错误强制当前客户端下线。知识点补充JWTJSON Web Token是一种开放标准RFC 7519用于在网络应用环境间安全地传递声明。它由三部分组成Header、Payload和Signature。本实现中通过Redis存储Token用于实现Token失效和多设备登录控制当用户登出或在其他设备登录时Redis中的Token会被删除或更新使旧Token失效。4. 上下文透传机制校验通过后拦截器将解析出的userClaims、username和userId存入HttpServletRequest的属性 (Attribute) 中。这种设计极其优雅下游 Controller 或 Service 层不再需要重新解析 Token直接通过request.getAttribute(userId)即可获取身份信息大幅降低性能开销。5. 统一的响应规范writeErrorResponse方法在处理认证失败时并没有抛出 401 或 403 的 HTTP 状态码而是统一将状态设置为 HTTP 200 (HttpServletResponse.SC_OK)。它将Result对象转为 JSON 写入响应流利用业务上的ErrorCode区分具体错误。这种设计非常契合现代前端框架如 Axios的全局响应拦截器处理习惯。知识点补充这种统一错误处理方式避免了HTTP状态码的混乱前端可以根据errorCode字段如2001表示未授权2003表示无权限进行相应的处理而不必依赖HTTP状态码。例如当返回2001时前端可以自动跳转到登录页面提高了用户体验。三、 全局 Web 配置WebConfig有了强大的拦截器我们还需要将其注册到 Spring 容器中并配置其拦截规则。WebConfig类实现了WebMvcConfigurer接口承担了路由规划、跨域处理和静态资源映射的职责。3.1 WebConfig 完整代码packagecom.xuan.common.config;importcom.xuan.common.interceptor.JwtInterceptor;importlombok.RequiredArgsConstructor;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.CorsRegistry;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;ConfigurationRequiredArgsConstructorpublicclassWebConfigimplementsWebMvcConfigurer{privatefinalJwtInterceptorjwtInterceptor;OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(jwtInterceptor).addPathPatterns(/api/admin/**).excludePathPatterns(/api/admin/auth/login,/doc.html,/webjars/**,/v3/api-docs/**,/swagger-resources/**);}OverridepublicvoidaddCorsMappings(CorsRegistryregistry){registry.addMapping(/**).allowedOriginPatterns(*).allowedMethods(GET,POST,PUT,DELETE,OPTIONS).allowedHeaders(*).allowCredentials(true).maxAge(3600);}OverridepublicvoidaddResourceHandlers(ResourceHandlerRegistryregistry){registry.addResourceHandler(/uploads/**).addResourceLocations(file:./uploads/);registry.addResourceHandler(/doc.html).addResourceLocations(classpath:/META-INF/resources/);registry.addResourceHandler(/webjars/**).addResourceLocations(classpath:/META-INF/resources/webjars/);}}3.2 核心配置剖析1. 拦截器路由分配通过重写addInterceptors方法我们将JwtInterceptor注册到系统中。精准打击addPathPatterns(/api/admin/**)明确指出只有后台管理接口需要经过严格的 JWT 校验。白名单放行excludePathPatterns排除了登录接口防止未登录用户无法获取 Token 的死循环。同时排除了 Swagger/Knife4j 的 API 文档及静态资源路径方便开发调试。知识点补充Spring MVC的拦截器机制允许在请求处理前后执行特定逻辑。通过addPathPatterns指定需要拦截的路径模式excludePathPatterns排除不需要拦截的路径。这种配置方式使后台管理API必须通过认证而登录接口等公共接口可以无需认证。2. 全局跨域支持 (CORS)通过addCorsMappings方法配置了强大的跨域策略允许所有源、所有方法和所有请求头。配合allowCredentials(true)允许携带凭证如 Cookie并设置maxAge(3600)缓存预检请求一小时有效提升了跨域握手性能。知识点补充CORS跨源资源共享是浏览器安全机制防止恶意网站通过脚本访问其他域的资源。Spring Boot通过CorsRegistry配置跨域策略allowCredentials(true)表示允许发送Cookie等凭证信息这对需要认证的API非常重要。maxAge设置预检请求的缓存时间减少浏览器发送预检请求的次数。3. 静态资源动静分离addResourceHandlers方法将对外暴露的 URL/uploads/**映射到了服务器本地的文件目录file:./uploads/。这在处理博客系统的文章插图、用户头像等本地上传文件时非常实用实现了基础的动静资源分离。同时也保障了 API 接口文档 UI 资源的正常加载。知识点补充Spring Boot默认将static、public等目录下的文件作为静态资源。通过addResourceHandlers可以自定义静态资源的访问路径file:./uploads/表示将/uploads/**请求映射到项目根目录下的uploads文件夹方便处理文件上传后的访问。四、 总结通过WebConfig的路由规划与跨域支持结合JwtInterceptor基于 JWT 和 Redis 的深度校验我们使用 Spring Boot 构建了一套既能防御未授权访问又能处理并发登录状态的高可用权限系统。这套体系结构清晰、职责单一、前后端交互友好为后续复杂的业务开发扫清了安全障碍。