后端开发鉴权系统是一种用于验证和授权用户访问后端资源的系统,在保障系统安全和资源合理访问方面起着关键作用,以下是关于它的详细介绍:
现代Web应用的鉴权挑战在微服务架构盛行的当下,传统Session鉴权机制面临扩展性差、跨域支持复杂等问题。下面将以SpringBoot为基础框架,详细讲解如何通过JWT(JSON Web Token)构建安全高效的鉴权系统,涵盖核心原理、完整实现路径及安全最佳实践。
特性 | Session-Cookie | JWT |
---|---|---|
状态管理 | 服务端存储 | 无状态 |
扩展性 | 集群需同步 | 天然支持分布式 |
跨域支持 | 需额外配置 | 原生支持CORS |
移动端适配 | Cookie处理复杂 | Header携带更友好 |
实现:
JSON Web Token Introduction - jwt.io
Base64: 是一种基于64个可打印字符(A-Z a-z 0-9 + = /)来表示二进制数据的编码方式
首先,确保你的 pom.xml
中包含了 Spring Boot Web 和 JWT 的相关依赖:
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>io.jsonwebtokengroupId>
<artifactId>jjwt-apiartifactId>
<version>0.11.5version>
dependency>
dependencies>
这个工具类包含了生成和解析 JWT 的方法。我们会使用一个密钥来签名 Token,并支持过期时间的设置。
import io.jsonwebtoken.*;
import java.util.Date;
import java.util.List;
import java.util.Base64;
public class JwtUtils {
// 密钥,用于加密和解密JWT
private static final String SECRET_KEY = Base64.getEncoder().encodeToString("your-256bit-secret".getBytes());
// Token有效期(1小时)
private static final long EXPIRATION_MS = 3600000;
// 生成Token
public static String generateToken(String username, List<String> roles) {
return Jwts.builder()
.setSubject(username) // 设置用户名
.claim("roles", roles) // 添加自定义主体信息
.setIssuedAt(new Date()) // 设置发行时间
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_MS)) // 设置过期时间
.signWith(SignatureAlgorithm.HS256, SECRET_KEY) // 使用HS256加密算法和密钥签名
.compact(); // 返回JWT
}
// 解析Token
public static Claims parseToken(String token) {
try {
return Jwts.parser()
.setSigningKey(SECRET_KEY) // 设置密钥进行解密
.parseClaimsJws(token) // 解析JWT
.getBody(); // 返回Token的主体部分(Claims)
} catch (ExpiredJwtException e) {
throw new RuntimeException("Token已过期");
} catch (Exception e) {
throw new RuntimeException("无效的Token");
}
}
}
我们需要一个拦截器来验证请求中的 JWT Token。所有需要认证的请求都会经过这个拦截器检查。
import io.jsonwebtoken.Claims;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class JwtInterceptor implements HandlerInterceptor {
// 处理请求前,检查Authorization头中的Token
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 获取Authorization头
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回401
response.getWriter().write("缺少有效的认证凭证");
return false;
}
try {
// 去掉 "Bearer " 前缀,获取实际的Token
Claims claims = JwtUtils.parseToken(token.substring(7)); // 解析Token
// 将解析后的用户信息放到request的属性中,以便后续使用
request.setAttribute("userClaims", claims);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回401
response.getWriter().write("Token无效或过期");
return false;
}
return true; // 继续执行下一个拦截器或控制器
}
}
接下来,我们需要将拦截器注册到 Spring MVC 配置中。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 将JwtInterceptor添加到拦截器链中
registry.addInterceptor(new JwtInterceptor())
.addPathPatterns("/protected/**") // 只拦截需要认证的接口(例如/protected/**)
.excludePathPatterns("/login", "/register"); // 不拦截登录和注册等无需认证的接口
}
}
创建一个简单的登录接口,成功登录后生成 JWT 返回给客户端。
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
@RestController
public class AuthController {
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
// 假设用户名和密码验证成功
String username = request.getUsername();
String password = request.getPassword();
// 生成JWT Token
String token = JwtUtils.generateToken(username, Arrays.asList("ROLE_USER"));
// 返回JWT
return ResponseEntity.ok(new AuthResponse(token));
}
}