赞
踩
JSON Web Token(JWT)是一种基于JSON的开放标准(RFC 7519),用于在各方之间以JSON对象的形式安全地传输信息。JWT可以被签名,确保信息在传输过程中的完整性和可信度。JWT通常用于身份验证和信息交换,特别适用于分布式系统和跨域认证场景。
官网地址:https://jwt.io/introduction/
中文网站:http://jwt.uihtm.com/
相较于传统的Session认证,JWT具有以下优势:
JWT由三部分组成,用.连接:
Header(头部信息):包含令牌的类型和所使用的签名算法。
Payload(有效载荷):包含所谓的Claims(声明),它们是关于实体(通常是用户)和其他数据的声明。
Signature(签名):用于验证消息在传输过程中未被篡改,并且,对于使用私钥签名的令牌,还可以验证发送者的身份。
因此,JWT 格式通常如下所示。
xxxxx.yyyyy.zzzzz
通常由两部分组成:令牌的类型,即 JWT,以及正在使用的签名算法,例如 HMAC SHA256 或 RSA。
{
"alg": "HS256",
"typ": "JWT"
}
然后,这个 JSON 被Base64Url编码以形成 JWT 的第一部分。
包含声明。声明是关于实体(通常是用户)和附加数据的陈述。索赔分为三种类型:注册索赔、公开索赔和私人索赔。
一个示例有效载荷可能是::
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
然后对有效负载进行Base64Url编码以形成 JSON Web 令牌的第二部分。
要创建签名部分,必须获取编码的标头、编码的有效负载、秘密、标头中指定的算法,并对其进行签名。
例如,如果想使用 HMAC SHA256 算法,签名将通过以下方式创建:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
签名用于验证消息在此过程中没有被更改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发送者就是它所说的那个人。
如果想玩 JWT 并将这些概念付诸实践,可以使用 jwt.io Debugger 来解码、验证和生成 JWT。
在SpringBoot项目的pom.xml中添加JWT的依赖,例如使用java-jwt库:
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.2</version> <!-- 请使用最新版本 -->
</dependency>
创建一个工具类来生成和验证JWT:
import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT; import java.util.Date; import java.util.HashMap; import java.util.Map; public class JwtTokenUtil { private String secret = "secretKey"; // 密钥 public String generateToken(String username) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + 1000 * 60 * 60); // 1小时后过期 Map<String, Object> claims = new HashMap<>(); claims.put("username", username); return JWT.create() .withIssuer("yourIssuer") // 发行人 .withIssuedAt(now) .withExpiresAt(expiryDate) .withClaim("username", username) .sign(Algorithm.HMAC256(secret)); } public String getUsername(String token) { DecodedJWT jwt = JWT.require(Algorithm.HMAC256(secret)).build().verify(token); return jwt.getClaim("username").asString(); } // 验证Token public boolean validateToken(String token, String username) { try { DecodedJWT jwt = JWT.require(Algorithm.HMAC256(secret)) .withClaim("username", username) .build() .verify(token); return true; } catch (Exception e) { return false; } } }
创建一个过滤器来拦截请求,并验证JWT的有效性:
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; @Component public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenUtil jwtTokenUtil; public JwtAuthenticationFilter(JwtTokenUtil jwtTokenUtil) { this.jwtTokenUtil = jwtTokenUtil; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { final String authorizationHeader = request.getHeader("Authorization"); String token = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { token = authorizationHeader.substring(7); } String username = null; boolean isTokenValid = false; if (token != null) { username = jwtTokenUtil.getUsername(token); isTokenValid = jwtTokenUtil.validateToken(token, username); } if (!isTokenValid) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return; } filterChain.doFilter(request, response); } }
创建一个用户登录接口,用于生成JWT:
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; @RestController public class AuthenticationController { private final JwtTokenUtil jwtTokenUtil; public AuthenticationController(JwtTokenUtil jwtTokenUtil) { this.jwtTokenUtil = jwtTokenUtil; } @PostMapping("/login") public Map<String, String> login(@RequestBody LoginRequest loginRequest) { String username = loginRequest.getUsername(); // 这里应该添加验证用户名和密码的逻辑 // 如果验证成功 String token = jwtTokenUtil.generateToken(username); Map<String, String> responseMap = new HashMap<>(); responseMap.put("token", token); return responseMap; } }
客户端(通常是浏览器)在收到JWT后,应将其存储在本地,如LocalStorage或SessionStorage中。在随后的请求中,客户端需要在HTTP请求头中添加JWT,以验证用户身份。
通过上述步骤,我们成功地在SpringBoot项目中集成了JWT,实现了API接口服务的身份验证。JWT提供了一种安全、高效的方式来处理身份验证和信息交换,特别适合于微服务和分布式系统。然而,需要注意的是,JWT不适用于需要高度安全的场景,如支付系统,因为JWT一旦发出,就无法撤销,除非等到它自然过期。此外,由于JWT通常存储在客户端,因此它们容易受到跨站脚本攻击(XSS)的影响。开发者应采取适当的安全措施来保护JWT,例如使用HttpOnly的Cookie标志来存储令牌,或者使用内容安全策略(CSP)来减轻XSS攻击的风险。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。