方案2:Spring Boot + Spring Security + JWT
从第一种方法你们肯定已经看出来了,权限控制的核心就是获取当前用户所拥有的权限,只要我们提供用户数据来源可以不实现 UserDetailsService,所以就有了这第二种方法的JWT。
(1)添加依赖 首先需要在 pom.xml 文件中添加 io.jsonwebtoken 库的依赖:
xml
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
(2)创建 JWT 工具类
java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Component
public class JwtUtil {
// 密钥,用于签名和验证 JWT,应妥善保管
private static final String SECRET_KEY = "yourSecretKey";
// JWT 的过期时间,这里设置为 10 小时
private static final long EXPIRATION_TIME = 1000 * 60 * 60 * 10;
// 根据用户详细信息生成 JWT
// 这里的userDetails可以是你自己定义的用户类
public String generateToken(UserDetails userDetails) {
//自定义的声明
Map<String, Object> claims = new HashMap<>();
//鉴权所需的权限角色
//userDetails.getIdentities()是List<String>的角色字符串列表
claims.put("identities",userDetails.getIdentities());
return createToken(claims, userDetails.getId());
}
// 创建 JWT 的具体方法
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)//自定义的声明
.setSubject(subject)//存的用户id
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
//解析jwt
public Claims extractAllClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY)
.build()
.parseClaimsJws(token)
.getBody();
}
}
(3)创建TokenFilter 创建TokenFilter过滤器来验证并解析jwt,从而获取权限信息
java
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
//获取token
final String authorizationHeader = request.getHeader("Authorization");
// 没有带token直接过去
if(authorizationHeader == null){
chain.doFilter(request, response);
}
//解析token
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
Claims claims;
try {
claims = jwtUtil.extractAllClaims(jwt);
} catch (IllegalArgumentException e) {
//解析 JWT 时发生其他错误
System.out.println("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
//JWT 已过期
System.out.println("JWT Token has expired");
}
}
//取出权限角色列表
Object identitiesObj = claims.get("identities");
List<GrantedAuthority> authorities = new ArrayList<>();
if (identitiesObj instanceof List) {
List<?> identitiesList = (List<?>) identitiesObj;
for (Object obj : identitiesList) {
if (obj instanceof String) {
authorities.add(new SimpleGrantedAuthority((String) obj));
}
}
}
String userId = claims.getSubject();
//将 Authentication 对象设置到 SecurityContextHolder 中后,Spring Security 就能在后续的授权过程中使用这些权限信息了。
Authentication authentication = new UsernamePasswordAuthenticationToken(userId, null, authorities);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(request, response);
}
}
(4)配置 Spring Security
java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/public/**").permitAll() // 公开接口
.requestMatchers("/user/**").hasAuthority("user") // 需具体权限
.anyRequest().authenticated() // 其他接口需登录
)
return http.build();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // 密码加密
}
}
现在就实现jwt的权限管理了。
对比2种方法总结: ✅ 优点 灵活性高:角色和权限可动态配置。 易于扩展:支持方法级和 URL 级权限控制。 适合单体应用:数据库存储权限,管理方便。 ❌ 缺点 微服务架构下重复鉴权:每个服务需单独校验权限(可结合 Gateway + JWT 优化)。