返回
Spring Boot与Shiro集成JWT的简洁指南
后端
2024-01-07 10:42:27
在现代Web应用程序开发中,安全性和认证至关重要。Spring Boot和Shiro是Java开发人员用来加强应用程序安全的流行框架。本文将深入探讨如何将Shiro与Spring Boot集成,并使用JSON Web令牌(JWT)进行身份验证。
前言
JWT是一种紧凑、自包含的令牌,用于在分布式系统中安全地传递身份验证信息。它由三部分组成:标头、有效载荷和签名。标头和有效载荷使用Base64编码,而签名则使用HMAC算法生成。
整合Shiro和JWT
要将Shiro与JWT集成,我们需要执行以下步骤:
-
添加依赖项: 在Maven或Gradle项目中添加以下依赖项:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.19.2</version> </dependency>
-
配置Shiro: 在
application.yml
文件中配置Shiro:shiro: jwt: secret: "my-secret-key" # 签名密钥 expiration: 604800000 # 过期时间(单位:毫秒)
-
创建Realm: 创建实现
Realm
接口的自定义Realm:@Service public class JwtRealm implements Realm { @Override public String getName() { return "JwtRealm"; } @Override public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String jwt = (String) token.getPrincipal(); // 验证JWT if (validateJwt(jwt)) { // 从有效载荷中提取身份信息 Claims claims = Jwts.parser() .setSigningKey(shiro.getJwt().getSecret().getBytes()) .parseClaimsJws(jwt) .getBody(); String username = claims.getSubject(); List<String> roles = (List<String>) claims.get("roles"); List<String> permissions = (List<String>) claims.get("permissions"); // 创建身份信息对象 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, jwt, getName()); info.setRoles(new HashSet<>(roles)); info.setPermissions(new HashSet<>(permissions)); return info; } return null; } // 验证JWT private boolean validateJwt(String jwt) { try { Jwts.parser() .setSigningKey(shiro.getJwt().getSecret().getBytes()) .parseClaimsJws(jwt); return true; } catch (Exception e) { return false; } } }
-
配置JWT过滤器: 创建实现
Filter
接口的自定义JWT过滤器:@WebFilter(urlPatterns = "/**") public class JwtFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String jwt = request.getHeader("Authorization"); if (jwt != null && jwt.startsWith("Bearer ")) { jwt = jwt.substring(7); // 验证JWT if (validateJwt(jwt)) { // 解析JWT并将其存储在安全上下文中 Claims claims = Jwts.parser() .setSigningKey(shiro.getJwt().getSecret().getBytes()) .parseClaimsJws(jwt) .getBody(); String username = claims.getSubject(); SecurityUtils.getSubject().login(new UsernamePasswordToken(username, jwt, false)); } } chain.doFilter(request, response); } // 验证JWT private boolean validateJwt(String jwt) { try { Jwts.parser() .setSigningKey(shiro.getJwt().getSecret().getBytes()) .parseClaimsJws(jwt); return true; } catch (Exception e) { return false; } } }
-
注册Realm和过滤器: 在Spring Boot应用程序的
main
方法中注册Realm和过滤器:@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); SecurityUtils.setSecurityManager(new DefaultSecurityManager(new JwtRealm())); SecurityUtils.getSubject().getSession().start(); } }
生成JWT
在认证成功后,我们可以使用Jwts
库生成JWT:
// 生成JWT
String jwt = Jwts.builder()
.setSubject(username) // 设置主题(用户标识)
.setIssuedAt(new Date()) // 设置签发时间
.setExpiration(new Date(System.currentTimeMillis() + shiro.getJwt().getExpiration())) // 设置过期时间
.claim("roles", roles) // 设置角色
.claim("permissions", permissions) // 设置权限
.signWith(SignatureAlgorithm.HS256, shiro.getJwt().getSecret().getBytes()) // 设置签名算法和密钥
.compact();
// 返回JWT
return jwt;
使用JWT
客户端可以将JWT作为Authorization
头的一部分发送给服务器,格式为Bearer {jwt}
。服务器将验证JWT并基于其内容授予访问权限。
总结
通过将Shiro与JWT集成,我们可以在Spring Boot应用程序中实现安全且无状态的身份验证。JWT的轻量级、自包含性和易于解析的特性使其成为分布式应用程序的理想选择。通过遵循本文中概述的步骤,开发者可以轻松地在他们的应用程序中实现JWT认证,从而增强其安全性并提高用户体验。