首页 > 网站 > 帮助中心 > 正文

Spring Security代码实现JWT接口权限授予与校验功能

2024-07-09 22:42:11
字体:
来源:转载
供稿:网友

通过笔者前两篇文章的说明,相信大家已经知道JWT是什么,怎么用,该如何结合Spring Security使用。那么本节就用代码来具体的实现一下JWT登录认证及鉴权的流程。

一、环境准备工作

建立Spring Boot项目并集成了Spring Security,项目可以正常启动 通过controller写一个HTTP的GET方法服务接口,比如:“/hello” 实现最基本的动态数据验证及权限分配,即实现UserDetailsService接口和UserDetails接口。这两个接口都是向Spring Security提供用户、角色、权限等校验信息的接口 如果你学习过Spring Security的formLogin登录模式,请将HttpSecurity配置中的formLogin()配置段全部去掉。因为JWT完全使用JSON接口,没有from表单提交。 HttpSecurity配置中一定要加上csrf().disable(),即暂时关掉跨站攻击CSRF的防御。这样是不安全的,我们后续章节再做处理。

以上的内容,我们在之前的文章中都已经讲过。如果仍然不熟悉,可以翻看本号之前的文章。

## 二、开发JWT工具类

通过maven坐标引入JWT工具包jjwt

<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version></dependency>

在application.yml中加入如下自定义一些关于JWT的配置

jwt:  header: JWTHeaderName secret: aabbccdd  expiration: 3600000 
其中header是携带JWT令牌的HTTP的Header的名称。虽然我这里叫做JWTHeaderName,但是在实际生产中可读性越差越安全。 secret是用来为JWT基础信息加密和解密的密钥。虽然我在这里在配置文件写死了,但是在实际生产中通常不直接写在配置文件里面。而是通过应用的启动参数传递,并且需要定期修改。 expiration是JWT令牌的有效时间。

写一个Spring Boot配置自动加载的工具类。

@Data@ConfigurationProperties(prefix = "jwt") //配置自动加载,prefix是配置的前缀@Componentpublic class JwtTokenUtil implements Serializable { private String secret; private Long expiration; private String header; /** * 生成token令牌 * * @param userDetails 用户 * @return 令token牌 */ public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(2); claims.put("sub", userDetails.getUsername()); claims.put("created", new Date()); return generateToken(claims); } /** * 从令牌中获取用户名 * * @param token 令牌 * @return 用户名 */ public String getUsernameFromToken(String token) { String username; try {  Claims claims = getClaimsFromToken(token);  username = claims.getSubject(); } catch (Exception e) {  username = null; } return username; } /** * 判断令牌是否过期 * * @param token 令牌 * @return 是否过期 */ public Boolean isTokenExpired(String token) { try {  Claims claims = getClaimsFromToken(token);  Date expiration = claims.getExpiration();  return expiration.before(new Date()); } catch (Exception e) {  return false; } } /** * 刷新令牌 * * @param token 原令牌 * @return 新令牌 */ public String refreshToken(String token) { String refreshedToken; try {  Claims claims = getClaimsFromToken(token);  claims.put("created", new Date());  refreshedToken = generateToken(claims); } catch (Exception e) {  refreshedToken = null; } return refreshedToken; } /** * 验证令牌 * * @param token 令牌 * @param userDetails 用户 * @return 是否有效 */ public Boolean validateToken(String token, UserDetails userDetails) { SysUser user = (SysUser) userDetails; String username = getUsernameFromToken(token); return (username.equals(user.getUsername()) && !isTokenExpired(token)); } /** * 从claims生成令牌,如果看不懂就看谁调用它 * * @param claims 数据声明 * @return 令牌 */ private String generateToken(Map<String, Object> claims) { Date expirationDate = new Date(System.currentTimeMillis() + expiration); return Jwts.builder().setClaims(claims)    .setExpiration(expirationDate)    .signWith(SignatureAlgorithm.HS512, secret)    .compact(); } /** * 从令牌中获取数据声明,如果看不懂就看谁调用它 * * @param token 令牌 * @return 数据声明 */ private Claims getClaimsFromToken(String token) { Claims claims; try {  claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } catch (Exception e) {  claims = null; } return claims; }}
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表