当前位置: 首页 > news >正文

身份认证状态的存储与传递( Spring Boot篇 )

在 Spring Boot 中,浏览器获取登录信息的核心是 “身份认证状态的存储与传递”——登录成功后,服务端会生成用户身份凭证,浏览器通过特定机制存储该凭证,后续请求时自动携带,服务端验证凭证后即可识别用户身份,返回对应的登录信息。

以下是主流实现方案,从原理到具体操作逐步说明:

一、核心逻辑:登录信息的“存储-传递-验证”流程

无论哪种方案,本质都是3步:

  1. 登录成功:用户提交账号密码,服务端验证通过后,生成包含用户身份(如用户ID、角色)的凭证(如Session ID、JWT Token);
  2. 凭证存储:服务端存储凭证与用户信息的关联(如Session内存、Redis),浏览器存储凭证(如Cookie、LocalStorage);
  3. 后续请求:浏览器携带凭证发起请求,服务端验证凭证有效性,从关联存储中取出用户信息,供业务使用(如返回用户昵称、权限)。

二、主流实现方案(按常用程度排序)

方案1:基于 Session + Cookie(传统经典方案)

这是 Spring Boot 整合 Spring Security/Shiro 时的默认方案,依赖 HTTP 协议的 Cookie 和服务端 Session 机制。

原理

  • Session:服务端创建的内存/持久化存储(如Redis),存储用户登录信息(用户ID、角色等),每个Session对应唯一的 JSESSIONID(凭证);
  • Cookie:浏览器自动存储 JSESSIONID,后续请求时自动在 HTTP 头的 Cookie 字段中携带该ID;
  • 流程
    1. 用户登录 → 服务端验证通过 → 创建 Session(存储用户信息)→ 响应时通过 Set-Cookie 头将 JSESSIONID 发送给浏览器;
    2. 浏览器保存 JSESSIONID 到 Cookie;
    3. 后续请求 → 浏览器自动携带 JSESSIONID(Cookie 字段)→ 服务端通过 JSESSIONID 找到对应的 Session → 取出用户登录信息。

代码实现(Spring Security 示例)

  1. 引入依赖(Spring Boot 2.x+):
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
  1. 配置 Spring Security(默认启用 Session + Cookie):
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {// 密码加密器(Spring Security 要求密码必须加密存储)@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}// 模拟用户(实际从数据库查询)@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("admin").password(passwordEncoder().encode("123456")).roles("ADMIN"); // 存储用户角色(登录信息的一部分)}// 授权规则(登录接口允许匿名访问)@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/login").permitAll() // 登录接口匿名访问.anyRequest().authenticated() // 其他接口需登录.and().formLogin() // 启用默认登录页面(或自定义 loginPage).defaultSuccessUrl("/user/info") // 登录成功后跳转的接口(获取登录信息).and().logout().permitAll();}
}
  1. 编写接口,获取当前登录用户信息:
@RestController
@RequestMapping("/user")
public class UserController {// 从 SecurityContext 中获取登录用户信息(Spring Security 自动注入)@GetMapping("/info")public Principal getLoginUser(Principal principal) {// Principal 包含用户名,如需更多信息(如用户ID、昵称),需自定义 User 类return principal;}
}
  1. 浏览器端表现:
  • 登录成功后,浏览器会在 Cookie 中存储 JSESSIONID
  • 后续访问 /user/info 时,浏览器自动携带 JSESSIONID,服务端验证后返回当前登录用户(如 {"name":"admin"})。

特点

  • 优点:简单易用,无需前端额外处理(Cookie 自动携带),安全性较高(可配置 Cookie 为 HttpOnly 防止 XSS 攻击);
  • 缺点:依赖 Cookie,跨域场景需额外配置(如 CORS + Credentials),分布式部署需共享 Session(如 Redis 存储 Session)。

方案2:基于 JWT Token(无状态方案,适合前后端分离/跨域)

JWT(JSON Web Token)是一种无状态凭证,登录成功后服务端生成 Token 并返回给浏览器,浏览器存储 Token(如 LocalStorage),后续请求通过 HTTP 头(如 Authorization: Bearer Token)携带 Token,服务端解析 Token 即可获取用户信息。

原理

  • JWT 结构:由 Header(算法)、Payload(用户信息,如用户ID、用户名)、Signature(签名,防止篡改)三部分组成,用 . 拼接;
  • 流程
    1. 用户登录 → 服务端验证通过 → 生成 JWT Token(Payload 中嵌入用户信息)→ 返回 Token 给浏览器;
    2. 浏览器将 Token 存储到 LocalStorage/SessionStorage;
    3. 后续请求 → 前端在请求头中添加 Authorization: Bearer ${Token} → 服务端验证 Token 签名(确保未篡改)→ 解析 Payload 中的用户信息。

代码实现(Spring Security + JWT)

  1. 引入依赖(除 Spring Security 外,需添加 JWT 依赖):
<!-- JWT 依赖 -->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version>
</dependency>
  1. 编写 JWT 工具类(生成 Token、验证 Token、解析用户信息):
@Component
public class JwtUtil {// 密钥(生产环境需配置在配置文件,且定期更换)private static final String SECRET = "your-secret-key-32bytes-long-123456";// Token 过期时间(如 2 小时)private static final long EXPIRATION = 7200000;// 生成 Token(登录成功后调用)public String generateToken(UserDetails userDetails) {Map<String, Object> claims = new HashMap<>();claims.put("username", userDetails.getUsername());claims.put("roles", userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()));return Jwts.builder().setClaims(claims).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION)).signWith(SignatureAlgorithm.HS256, SECRET).compact();}// 验证 Token 有效性public boolean validateToken(String token) {try {Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token);return true;} catch (Exception e) {return false;}}// 从 Token 中解析用户信息(如用户名)public String getUsernameFromToken(String token) {Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();return (String) claims.get("username");}
}
  1. 配置 Spring Security(禁用 Session,使用 JWT 认证):
@Configuration
@EnableWebSecurity
public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtUtil jwtUtil;@Autowiredprivate UserDetailsService userDetailsService; // 自定义用户查询服务(从数据库取用户)// 认证过滤器:解析请求头中的 Token,验证后注入用户信息到 SecurityContext@Beanpublic JwtAuthenticationFilter jwtAuthenticationFilter() {return new JwtAuthenticationFilter(jwtUtil, userDetailsService);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable() // 前后端分离场景禁用 CSRF(Token 本身已防篡改).sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 禁用 Session.and().authorizeRequests().antMatchers("/login").permitAll().anyRequest().authenticated().and().addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); // 添加 JWT 过滤器}
}
  1. 登录接口(生成 Token 并返回):
@RestController
public class LoginController {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate JwtUtil jwtUtil;@PostMapping("/login")public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {// 验证账号密码Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));SecurityContextHolder.getContext().setAuthentication(authentication);// 生成 JWT TokenUserDetails userDetails = (UserDetails) authentication.getPrincipal();String token = jwtUtil.generateToken(userDetails);// 返回 Token 给浏览器return ResponseEntity.ok(new JwtResponse(token));}
}// 接收登录请求的实体类
@Data
class LoginRequest {private String username;private String password;
}// 返回 Token 的实体类
@Data
class JwtResponse {private String token;public JwtResponse(String token) {this.token = token;}
}
  1. 浏览器端处理:
  • 登录成功后,前端将 Token 存储到 localStorage
    // 登录请求
    fetch('/login', {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({username: 'admin', password: '123456'})
    })
    .then(res => res.json())
    .then(data => {localStorage.setItem('token', data.token); // 存储 Token
    });// 后续请求(携带 Token)
    fetch('/user/info', {headers: {'Authorization': `Bearer ${localStorage.getItem('token')}` // 携带 Token}
    })
    .then(res => res.json())
    .then(userInfo => console.log('登录用户信息:', userInfo));
    

特点

  • 优点:无状态(服务端无需存储 Session),支持跨域、分布式部署(Token 自带用户信息),适合前后端分离项目;
  • 缺点:Token 一旦生成无法主动撤销(需通过过期时间控制或维护黑名单),Payload 不加密(敏感信息需加密存储),前端需手动处理 Token 存储与携带。

方案3:基于 OAuth2.0/OIDC(第三方登录,如微信、QQ、GitHub)

如果需要支持第三方登录(用户无需注册,通过微信/QQ 等账号登录),则使用 OAuth2.0 + OIDC 协议,浏览器通过第三方授权获取身份凭证,服务端验证后获取用户信息。

核心流程

  1. 浏览器跳转第三方授权页面(如微信登录页);
  2. 用户授权后,第三方平台返回 code 给浏览器;
  3. 浏览器将 code 发送给后端,后端通过 code 向第三方平台请求 access_token
  4. 后端用 access_token 调用第三方平台的用户信息接口(如微信的 /sns/userinfo),获取用户昵称、头像等信息;
  5. 后端将第三方用户信息与本地用户关联(或自动注册),生成本地登录凭证(如 Session/JWT),返回给浏览器。

代码实现(Spring Security OAuth2.0 示例,以 GitHub 登录为例)

  1. 引入依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
  1. 配置 GitHub OAuth2.0 信息(application.yml):
spring:security:oauth2:client:registration:github:client-id: 你的GitHub客户端ID(从GitHub开发者平台申请)client-secret: 你的GitHub客户端密钥scope: user:email,read:user # 申请的权限(获取用户邮箱、基本信息)provider:github:user-info-uri: https://api.github.com/useremail-attribute-name: email
  1. 配置 Spring Security(启用 OAuth2.0 登录):
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().oauth2Login() // 启用 OAuth2.0 登录.defaultSuccessUrl("/user/info", true) // 登录成功后跳转获取用户信息.userInfoEndpoint().userService(customOAuth2UserService); // 自定义用户信息处理(关联本地用户)}
}
  1. 获取登录用户信息接口:
@RestController
@RequestMapping("/user")
public class UserController {@GetMapping("/info")public OAuth2User getLoginUser(Authentication authentication) {// OAuth2User 包含第三方用户信息(如GitHub昵称、头像、ID)return (OAuth2User) authentication.getPrincipal();}
}
  1. 浏览器端表现:
  • 访问 /user/info 时,自动跳转 GitHub 登录页;
  • 用户登录授权后,跳转回 /user/info,返回 GitHub 用户信息(如昵称、头像URL)。

三、关键注意点

  1. 安全性

    • Session + Cookie:配置 Cookie 为 HttpOnly(防止 XSS 攻击)、Secure(仅 HTTPS 传输)、SameSite(防止 CSRF 攻击);
    • JWT:密钥需足够复杂且定期更换,敏感信息(如密码)不能存入 Payload(Payload 可解码),Token 过期时间不宜过长;
    • 所有方案都建议使用 HTTPS 传输,防止凭证被窃取。
  2. 用户信息扩展

    • 默认的 Principal/UserDetails 仅包含用户名和角色,如需用户ID、昵称、邮箱等信息,需自定义 User 类实现 UserDetails,并在登录时注入。
  3. 跨域处理

    • Session + Cookie:跨域时需配置 CORS 允许 credentials(凭证),前端请求需携带 withCredentials: true
    • JWT:无跨域限制(Token 通过请求头携带),只需配置 CORS 允许 Authorization 头。
  4. 分布式部署

    • Session + Cookie:需将 Session 存储到共享介质(如 Redis),通过 spring-session-data-redis 依赖实现;
    • JWT:天然支持分布式(无状态),无需额外配置。

总结

  • 传统项目/非前后端分离:优先使用 Session + Cookie(简单、安全、无需前端额外处理);
  • 前后端分离/跨域/分布式项目:优先使用 JWT Token(无状态、易扩展);
  • 第三方登录场景:使用 OAuth2.0/OIDC(对接微信、GitHub 等平台)。

无论哪种方案,浏览器获取登录信息的核心都是通过凭证关联服务端的用户身份,差异仅在于凭证的存储方式(Cookie/LocalStorage)和传递方式(自动携带/手动添加请求头)。

http://www.jsqmd.com/news/42849/

相关文章:

  • 国标GB28181算法算力平台EasyGBS打造园区智能化安防监控高效解决方案
  • 20232306 2025-2026-1 《网络与系统攻防技术》实验六实验报告
  • 数据库基础(lab5:单表查询 三)
  • ubuntu18解决 libc.so.6: version `GLIBC_2.28‘ not found
  • current linux
  • curl linux 命令
  • 堆贪心
  • 聚焦广州少儿编程机构实力榜TOP5!课程/师资/赛事成果大公开,高性价比品牌全测评
  • 20232409 2025-2026-1 《网络与系统攻防技术》实验八实验报告
  • 2025年最受欢迎上门家教老师排行榜,上门家教/一对一家教老师口碑推荐榜
  • 是时候从 MySQL 转到 PostgreSQL 18 了
  • 小程序客服系统客服软件--如何接入ttkefu
  • count函数在oracle中的使用场景有哪些
  • Photoshop下载教程(附2025最新版安装步骤与完整图文讲解)
  • makefile入门3 目标自动生成与模式规则
  • 2025年不锈钢网带链板制造企业权威推荐榜单:不锈钢平顶链板/ 链板/304不锈钢链板源头厂家精选
  • 算法课 PA2 T1
  • 上海少儿编程哪家靠谱?高性价比机构综合测评,妙小程+4大优质机构,覆盖信奥赛与AI编程
  • OpenAI Responses API 的战略意图与技术架构:AI 智能体时代的技术范式变革
  • JDK17 ProcessBuilder执行脚本报错 error=13
  • 2025年高抗冲阻燃PC/ABS定制厂家权威推荐榜单:低灰分阻燃PC/ABS/ GB4943.1-2022阻燃PC/ABS/5G基站阻燃PC/ABS源头厂家精选
  • 关于 Visual Studio 类模板、文件权限信息配置
  • 从传统架构到AI原生:深度剖析企业AI落地的“三高”痛点与Serverless化解决方案
  • skynet(v1.4.0)学习笔记
  • 网站推荐!夸克资源网站里面的夸克资源社!
  • 【20章】MCP+A2A 从0到1构建商业级多Agent全栈应用
  • 2025北京少儿编程机构实力榜单!妙小程逻辑思维提升/信奥赛冲刺/全年龄段课程可选
  • 优化的高光谱解混算法实现
  • 2025.11.17——1绿2蓝
  • 2025年CNBD权威公开:淮安婚纱照拍摄十佳机构专业评测,弥素摄影工作室蝉联冠军宝座