java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Boot身份认证状态存储与传递

Spring Boot身份认证状态的存储与传递实现方案

作者:编程改变生活

本文主要内容介绍了在SpringBoot中实现用户登录信息获取的三种主流方案:基于Session+Cookie、基于JWTToken和基于OAuth2.0/OIDC,并详细介绍了每种方案的核心逻辑、代码实现、优缺点及关键注意点,感兴趣的朋友跟随小编一起看看吧

在 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 机制。

原理

代码实现(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 要求密码必须加密存储)
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    // 模拟用户(实际从数据库查询)
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("admin")
            .password(passwordEncoder().encode("123456"))
            .roles("ADMIN"); // 存储用户角色(登录信息的一部分)
    }
    // 授权规则(登录接口允许匿名访问)
    @Override
    protected 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. 浏览器端表现:

特点

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

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

原理

代码实现(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 {
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private UserDetailsService userDetailsService; // 自定义用户查询服务(从数据库取用户)
    // 认证过滤器:解析请求头中的 Token,验证后注入用户信息到 SecurityContext
    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter(jwtUtil, userDetailsService);
    }
    @Override
    protected 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 {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private 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 Token
        UserDetails 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. 浏览器端处理:

特点

方案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/user
            email-attribute-name: email
  1. 配置 Spring Security(启用 OAuth2.0 登录):
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected 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. 浏览器端表现:

三、关键注意点

总结

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

到此这篇关于Spring Boot身份认证状态的存储与传递实现方案的文章就介绍到这了,更多相关Spring Boot身份认证状态存储与传递内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文