那我将为你详细讲解“详解Spring Boot实战之Filter实现使用JWT进行接口认证”的完整攻略。
1. 前言
在Web应用程序中,为了保障接口安全和数据的完整性,我们需要对访问接口的用户进行认证和授权。Spring Boot框架提供了多种认证和授权方式,其中,JWT是一种较为流行的认证方式。本文将通过Spring Boot实战教程来详细讲解如何使用Filter实现使用JWT进行接口认证。
2. JWT简介
JWT是Json Web Token的缩写,是一个轻量级的认证协议。它将用户身份信息以JSON格式保存在Token中,并使用密钥进行签名。在认证过程中,服务端只需对Token进行验证,从而达到用户认证和授权的目的。JWT的优点是不依赖Session,可以跨域传输。
JWT有3部分组成,分别是Header、Payload和Signature:
- Header:Token的头部,包含算法和类型等信息;
- Payload:Token的有效载荷,用于存储用户信息和其他用户相关的元数据;
- Signature:尾部是用于验证Token是否被篡改的签名。
3. 实现步骤
3.1 引入相关依赖
在spring boot项目中,使用JWT需要引入json-web-token和jackson-databind两个依赖。在pom.xml
文件中添加以下内容:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.7</version>
</dependency>
3.2 编写Token工具类
Token工具类用于生成和解析Token。在本例中,使用HS512算法和特定的密钥对Token进行签名,密钥采用硬编码方式存储。
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;
@Component
public class JwtTokenUtils {
// 过期时间30分钟
private static final long EXPIRATION_TIME = 30 * 60 * 1000;
// 密钥,硬编码,之后应该改为动态获取
private static final String SECRET = "jwt_secret";
/**
* 生成Token
* @param claims 载荷
* @return Token
*/
public static String generateToken(Map<String,Object> claims){
Date now = new Date();
Date expireDate = new Date(now.getTime() + EXPIRATION_TIME);
JwtBuilder builder = Jwts.builder().setClaims(claims)
.setExpiration(expireDate)
.signWith(SignatureAlgorithm.HS512, SECRET);
return builder.compact();
}
/**
* 解析Token
* @param token Token
* @return 用户id
*/
public static String getUserId(String token){
try {
Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
return claims.getSubject();
} catch (ExpiredJwtException e){
throw new RuntimeException("登录已过期,请重新登录");
} catch (UnsupportedJwtException e) {
throw new RuntimeException("不支持该JWT类型");
} catch (MalformedJwtException e) {
throw new RuntimeException("无效的JWT token");
} catch (SignatureException e) {
throw new RuntimeException("无效的签名");
} catch (IllegalArgumentException e) {
throw new RuntimeException("参数错误");
}
}
}
3.3 实现Filter
Filter是Servlet中的一种组件,它可以对请求和响应进行拦截和处理。在本例中,Filter的作用是对访问受保护接口的请求进行认证和授权。认证通过后,会将用户信息保存到Request对象中,方便后续操作使用。
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String path = request.getServletPath();
if (!path.startsWith("/api/")) {
chain.doFilter(request, response);
return;
}
String token = request.getHeader("Authorization");
if (token != null && token.startsWith("Bearer ")) {
try {
token = token.substring(7);
String userId = JwtTokenUtils.getUserId(token);
Map<String, Object> user = getUserInfoFromDb(userId);
if (user == null) {
response.setStatus(401);
return;
} else {
request.setAttribute("user", user);
chain.doFilter(request, response);
return;
}
} catch (Exception e) {
response.setStatus(401);
return;
}
} else {
response.setStatus(401);
return;
}
}
private Map<String, Object> getUserInfoFromDb(String userId){
// TODO: 从数据库获取用户信息
return null;
}
}
3.4 注册Filter
使用Spring Boot,我们可以通过在配置类中添加Filter进行注册。在本例中,需要使用FilterRegistrationBean
将Filter添加到过滤器链中。
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JwtConfig {
@Bean
public FilterRegistrationBean<JwtAuthenticationFilter> jwtAuthenticationFilter(){
FilterRegistrationBean<JwtAuthenticationFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new JwtAuthenticationFilter());
registrationBean.addUrlPatterns("/api/*");
return registrationBean;
}
}
4. 示例
为了方便演示,我们假设有一个用户注册和登陆接口,分别是:
POST /api/register
POST /api/login
其中,/api/login
接口返回JWT Token。假设用户ID和用户名存储在用户信息表中,getUserInfoFromDb()
方法从用户信息表中获取用户信息。
以下是注册和登录接口的示例代码。
4.1 注册接口
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@RestController
public class RegisterController {
@RequestMapping("/api/register")
public Map<String,Object> register(@RequestBody Map<String,Object> params){
String userId = UUID.randomUUID().toString();
String username = (String) params.get("username");
String password = (String) params.get("password");
// TODO: 将用户信息存入数据库
Map<String,Object> response = new HashMap<>();
response.put("code", 200);
response.put("msg", "注册成功");
return response;
}
}
4.2 登录接口
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class LoginController {
@RequestMapping("/api/login")
public Map<String,Object> login(@RequestBody Map<String,Object> params){
String username = (String) params.get("username");
String password = (String) params.get("password");
// TODO: 验证用户名和密码,从数据库获取用户信息
String userId = "fake_user_id";
Map<String,Object> claims = new HashMap<>();
claims.put("sub", userId);
String token = JwtTokenUtils.generateToken(claims);
Map<String,Object> response = new HashMap<>();
response.put("code", 200);
response.put("msg", "登录成功");
response.put("token", "Bearer "+token);
return response;
}
}
以上示例中,我给出了简单的用户注册和登录逻辑,只是为了方便演示。实际使用过程中,需要根据实际情况进行相应的修改和完善。
5. 总结
本文通过一个实际的例子,讲解了如何使用Filter实现使用JWT进行接口认证。在实现过程中,我们使用了Java JWT和Spring Boot等技术,包括编写Token工具类、实现Filter以及注册Filter等操作。JWT的优点在于不依赖Session,可以跨域传输。在使用JWT时,我们需要注意密钥管理、过期时间设置等问题,保证Token的安全有效。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Spring Boot实战之Filter实现使用JWT进行接口认证 - Python技术站