✨ 生成JWT令牌
This commit is contained in:
parent
4a43bf26b8
commit
f803241c78
|
@ -1355,3 +1355,169 @@ public class AuthenticationEvents {
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 实现JWT的认证
|
||||
|
||||
### 生成JWT令牌
|
||||
|
||||
> [!TIP]
|
||||
>
|
||||
> 如果需要JWTUtil工具类需要到项目的`com.spring.step2.utils.JwtTokenUtil`下寻找。
|
||||
|
||||
在Spring的配置文件中写入下面的内容。
|
||||
|
||||
```yaml
|
||||
jwtToken:
|
||||
# 密钥
|
||||
secret: aVeryLongAndSecureRandomStringWithAtLeast32Characters
|
||||
# 主题
|
||||
subject: SecurityBunny
|
||||
# 过期事件 7天
|
||||
expired: 604800
|
||||
```
|
||||
|
||||
之后要读取配置文件中的信息。
|
||||
|
||||
在文件中包含三个方法,分别是:创建令牌,解析令牌为用户名,解析令牌为用户Id。
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "jwt-token")
|
||||
public class JwtBearTokenService {
|
||||
|
||||
@Value("${jwtToken.secret}")
|
||||
public String secret;
|
||||
|
||||
@Value("${jwtToken.subject}")
|
||||
public String subject;
|
||||
|
||||
// private final SecretKey securityKey = Keys.hmacShaKeyFor("Bunny-Auth-Server-Private-SecretKey".getBytes(StandardCharsets.UTF_8));
|
||||
// JWT 的 秘钥
|
||||
@Value("${jwtToken.expired}")
|
||||
public Long expired;
|
||||
|
||||
/**
|
||||
* 创建Token
|
||||
*
|
||||
* @param userId 用户Id
|
||||
* @param username 用户名
|
||||
* @return 令牌Token
|
||||
*/
|
||||
public String createToken(Long userId, String username,
|
||||
List<String> roles, List<String> permissions) {
|
||||
SecretKey key = getSecretKey();
|
||||
// return JwtTokenUtil.createToken(userId, username, subject, key, expired);
|
||||
return JwtTokenUtil.createToken(userId, username, roles, permissions, subject, key, expired);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取安全密钥
|
||||
*
|
||||
* @return {@link SecretKey}
|
||||
*/
|
||||
private SecretKey getSecretKey() {
|
||||
byte[] secretBytes = secret.getBytes(StandardCharsets.UTF_8);
|
||||
return new SecretKeySpec(secretBytes, "HmacSHA256");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Token获取用户名
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户名
|
||||
*/
|
||||
public String getUsernameFromToken(String token) {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
return JwtTokenUtil.getUsername(token, secretKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Token获取用户Id
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户Id
|
||||
*/
|
||||
public Long getUserIdFromToken(String token) {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
return JwtTokenUtil.getUserId(token, secretKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Token获取用户Id
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户Id
|
||||
*/
|
||||
public Map<String, Object> getMapByToken(String token) {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
return JwtTokenUtil.getMapByToken(token, secretKey);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
之后对方法进行测试。
|
||||
|
||||
```java
|
||||
@SpringBootTest
|
||||
class JwtBearTokenServiceTest {
|
||||
|
||||
private String token;
|
||||
|
||||
@Autowired
|
||||
private JwtBearTokenService jwtBearTokenService;
|
||||
|
||||
@Autowired
|
||||
private DbUserDetailService dbUserDetailService;
|
||||
|
||||
@Test
|
||||
void createToken() {
|
||||
long userId = 1944384432521744386L;
|
||||
List<String> roles = dbUserDetailService.findUserRolesByUserId(userId);
|
||||
List<String> permissions = dbUserDetailService.findPermissionByUserId(userId);
|
||||
|
||||
String token = jwtBearTokenService.createToken(userId,
|
||||
"Bunny",
|
||||
roles,
|
||||
permissions);
|
||||
this.token = token;
|
||||
System.out.println(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUsernameFromToken() {
|
||||
createToken();
|
||||
|
||||
String username = jwtBearTokenService.getUsernameFromToken(token);
|
||||
System.out.println(username);
|
||||
|
||||
Long userId = jwtBearTokenService.getUserIdFromToken(token);
|
||||
System.out.println(userId);
|
||||
|
||||
Map<String, Object> map = jwtBearTokenService.getMapByToken(token);
|
||||
|
||||
List<?> roles = (List<?>) map.get("roles");
|
||||
System.out.println(roles);
|
||||
|
||||
// 安全转换 permissions
|
||||
List<?> permissions = (List<?>) map.get("permissions");
|
||||
System.out.println(permissions);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
输出以下内容:
|
||||
|
||||
```properties
|
||||
# 生成的令牌
|
||||
eyJ6aXAiOiJHWklQIiwiYWxnIjoiSFMyNTYifQ.H4sIAAAAAAAA_0WMzQ6CMBCE32XPNIHSH-hNowcOepB4Mh5qWRKMFNLSRGJ8d6tiPEyyM7PzPcCHCyio0QTXTfM6WDtDAngfQWWSU16yjLMEgkdXNTErGcuLKMppJt-3-JZW9xhBP4AbbuhBnWC12VX7GBzr7QHOCYzo-s77brCf-m-VcqibZbqY-H-duojFFAUvTUtaqTVhVEpSmEIQnjV5m_NUtIbC8wV0LG6kzgAAAA.lf4TXuafIQ2X5Ec3CsKR5ZN3q9KpJkeEBiYQbmNMuoQ
|
||||
# 解析的用户名
|
||||
Bunny
|
||||
# 解析的用户Id
|
||||
1944384432521744386
|
||||
# 解析的用户角色
|
||||
[ADMIN, USER]
|
||||
# 解析的用户权限
|
||||
[permission::read, role::read]
|
||||
```
|
||||
|
||||
|
|
|
@ -19,9 +19,15 @@
|
|||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<java.version>17</java.version>
|
||||
<jwt.version>0.12.6</jwt.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!--jjwt-->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>${jwt.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -37,7 +37,7 @@ public class DbUserDetailService implements UserDetailsService {
|
|||
Long userId = userEntity.getId();
|
||||
|
||||
// 设置用户角色
|
||||
String[] roles = findUserRolesByUserId(userId);
|
||||
String[] roles = findUserRolesByUserId(userId).toArray(String[]::new);
|
||||
|
||||
// 设置用户权限
|
||||
List<String> permissionsByUserId = findPermissionByUserId(userId);
|
||||
|
@ -66,9 +66,9 @@ public class DbUserDetailService implements UserDetailsService {
|
|||
* @param userId 用户id
|
||||
* @return 当前用户的角色信息
|
||||
*/
|
||||
public String[] findUserRolesByUserId(Long userId) {
|
||||
public List<String> findUserRolesByUserId(Long userId) {
|
||||
List<RoleEntity> roleList = userMapper.selectRolesByUserId(userId);
|
||||
return roleList.stream().map(RoleEntity::getRoleCode).toArray(String[]::new);
|
||||
return roleList.stream().map(RoleEntity::getRoleCode).toList();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package com.spring.step2.security.service;
|
||||
|
||||
import com.spring.step2.utils.JwtTokenUtil;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "jwt-token")
|
||||
public class JwtBearTokenService {
|
||||
|
||||
@Value("${jwtToken.secret}")
|
||||
public String secret;
|
||||
|
||||
@Value("${jwtToken.subject}")
|
||||
public String subject;
|
||||
|
||||
// private final SecretKey securityKey = Keys.hmacShaKeyFor("Bunny-Auth-Server-Private-SecretKey".getBytes(StandardCharsets.UTF_8));
|
||||
// JWT 的 秘钥
|
||||
@Value("${jwtToken.expired}")
|
||||
public Long expired;
|
||||
|
||||
/**
|
||||
* 创建Token
|
||||
*
|
||||
* @param userId 用户Id
|
||||
* @param username 用户名
|
||||
* @return 令牌Token
|
||||
*/
|
||||
public String createToken(Long userId, String username,
|
||||
List<String> roles, List<String> permissions) {
|
||||
SecretKey key = getSecretKey();
|
||||
// return JwtTokenUtil.createToken(userId, username, subject, key, expired);
|
||||
return JwtTokenUtil.createToken(userId, username, roles, permissions, subject, key, expired);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取安全密钥
|
||||
*
|
||||
* @return {@link SecretKey}
|
||||
*/
|
||||
private SecretKey getSecretKey() {
|
||||
byte[] secretBytes = secret.getBytes(StandardCharsets.UTF_8);
|
||||
return new SecretKeySpec(secretBytes, "HmacSHA256");
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Token获取用户名
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户名
|
||||
*/
|
||||
public String getUsernameFromToken(String token) {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
return JwtTokenUtil.getUsername(token, secretKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Token获取用户Id
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户Id
|
||||
*/
|
||||
public Long getUserIdFromToken(String token) {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
return JwtTokenUtil.getUserId(token, secretKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Token获取用户Id
|
||||
*
|
||||
* @param token 令牌
|
||||
* @return 用户Id
|
||||
*/
|
||||
public Map<String, Object> getMapByToken(String token) {
|
||||
SecretKey secretKey = getSecretKey();
|
||||
return JwtTokenUtil.getMapByToken(token, secretKey);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
package com.spring.step2.utils;
|
||||
|
||||
|
||||
import com.spring.step2.domain.vo.result.ResultCodeEnum;
|
||||
import com.spring.step2.exception.SecurityException;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jws;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.micrometer.common.lang.Nullable;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@Slf4j
|
||||
public class JwtTokenUtil {
|
||||
|
||||
/**
|
||||
* 使用默认主题,默认秘钥,自定义时间,创建集合形式token
|
||||
*
|
||||
* @param map 集合
|
||||
* @param day 过期时间
|
||||
* @return token
|
||||
*/
|
||||
public static String createTokenWithMap(Map<String, Object> map, String subject, SecretKey key, Long day) {
|
||||
return Jwts.builder()
|
||||
.subject(subject)
|
||||
.signWith(key)
|
||||
.expiration(new Date(System.currentTimeMillis() + day))
|
||||
.claims(map)
|
||||
.id(UUID.randomUUID().toString())
|
||||
.compressWith(Jwts.ZIP.GZIP).compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用自定义主题,自定义时间,创建集合形式token
|
||||
*
|
||||
* @param map 集合
|
||||
* @param subject 主题
|
||||
* @param time 过期时间
|
||||
* @return token
|
||||
*/
|
||||
public static String createTokenWithMap(Map<String, Object> map, String subject, SecretKey key, Date time) {
|
||||
return Jwts.builder()
|
||||
.subject(subject)
|
||||
.expiration(time)
|
||||
.claims(map)
|
||||
.id(UUID.randomUUID().toString())
|
||||
.signWith(key)
|
||||
.compressWith(Jwts.ZIP.GZIP).compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建集合形式token
|
||||
*
|
||||
* @param map 集合
|
||||
* @param subject 主题
|
||||
* @param day 过期时间
|
||||
* @return token
|
||||
*/
|
||||
public static String createTokenWithMap(Map<String, Object> map, String subject, SecretKey key, Integer day) {
|
||||
return Jwts.builder()
|
||||
.subject(subject)
|
||||
.expiration(new Date(System.currentTimeMillis() + day))
|
||||
.claims(map)
|
||||
.id(UUID.randomUUID().toString())
|
||||
.signWith(key)
|
||||
.compressWith(Jwts.ZIP.GZIP).compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名和ID创建token
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param username 用户名
|
||||
* @param day 过期时间
|
||||
* @return token值
|
||||
*/
|
||||
public static String createToken(Long userId, String username, String subject, SecretKey key, Long day) {
|
||||
return Jwts.builder()
|
||||
.subject(subject)
|
||||
.expiration(new Date(System.currentTimeMillis() + day))
|
||||
.claim("userId", userId)
|
||||
.claim("username", username)
|
||||
.id(UUID.randomUUID().toString())
|
||||
.signWith(key)
|
||||
.compressWith(Jwts.ZIP.GZIP).compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名和ID创建token
|
||||
* 在载体中添加角色和权限
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param username 用户名
|
||||
* @param day 过期时间
|
||||
* @return token值
|
||||
*/
|
||||
public static String createToken(Long userId, String username,
|
||||
List<String> roles, List<String> permissions,
|
||||
String subject, SecretKey key, Long day) {
|
||||
return Jwts.builder()
|
||||
.subject(subject)
|
||||
.expiration(new Date(System.currentTimeMillis() + day))
|
||||
.claim("userId", userId)
|
||||
.claim("username", username)
|
||||
.claim("roles", roles)
|
||||
.claim("permissions", permissions)
|
||||
.id(UUID.randomUUID().toString())
|
||||
.signWith(key)
|
||||
.compressWith(Jwts.ZIP.GZIP).compact();
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用token获取map集合,使用默认秘钥
|
||||
*
|
||||
* @param token token
|
||||
* @return map集合
|
||||
*/
|
||||
public static Map<String, Object> getMapByToken(String token, SecretKey key) {
|
||||
try {
|
||||
if (!StringUtils.hasText(token)) throw new SecurityException(ResultCodeEnum.TOKEN_PARSING_FAILED);
|
||||
// 将 body 值转为map
|
||||
return Jwts.parser().verifyWith(key).build().parseSignedClaims(token).getPayload();
|
||||
|
||||
} catch (Exception exception) {
|
||||
throw new SecurityException(ResultCodeEnum.TOKEN_PARSING_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getSubjectByTokenHandler(String token, SecretKey key) {
|
||||
try {
|
||||
if (!StringUtils.hasText(token)) throw new SecurityException(ResultCodeEnum.TOKEN_PARSING_FAILED);
|
||||
Jws<Claims> claimsJws = Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
|
||||
Claims body = claimsJws.getPayload();
|
||||
|
||||
return body.getSubject();
|
||||
|
||||
} catch (Exception exception) {
|
||||
throw new SecurityException(ResultCodeEnum.TOKEN_PARSING_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据token获取主题
|
||||
*
|
||||
* @param token token
|
||||
* @return 主题
|
||||
*/
|
||||
public static String getSubjectByToken(String token, SecretKey key) {
|
||||
return getSubjectByTokenHandler(token, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据token获取用户ID
|
||||
*
|
||||
* @param token token
|
||||
* @return 用户ID
|
||||
*/
|
||||
public static Long getUserId(String token, SecretKey key) {
|
||||
try {
|
||||
if (!StringUtils.hasText(token)) throw new SecurityException(ResultCodeEnum.TOKEN_PARSING_FAILED);
|
||||
|
||||
Jws<Claims> claimsJws = Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
|
||||
Claims claims = claimsJws.getPayload();
|
||||
|
||||
return Long.valueOf(String.valueOf(claims.get("userId")));
|
||||
} catch (Exception exception) {
|
||||
throw new SecurityException(ResultCodeEnum.TOKEN_PARSING_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据token获取用户名
|
||||
*
|
||||
* @param token token
|
||||
* @return 用户名
|
||||
*/
|
||||
public static String getUsername(String token, SecretKey key) {
|
||||
try {
|
||||
if (!StringUtils.hasText(token)) return "";
|
||||
|
||||
Jws<Claims> claimsJws = Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
|
||||
Claims claims = claimsJws.getPayload();
|
||||
return (String) claims.get("username");
|
||||
} catch (Exception exception) {
|
||||
throw new SecurityException(ResultCodeEnum.TOKEN_PARSING_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断token是否过期
|
||||
*
|
||||
* @param token token
|
||||
* @return 是否过期
|
||||
*/
|
||||
public static boolean isExpired(String token, SecretKey key) {
|
||||
return isExpiredUtil(token, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否过期
|
||||
*
|
||||
* @param token token
|
||||
* @return 是否过期
|
||||
*/
|
||||
private static boolean isExpiredUtil(String token, SecretKey key) {
|
||||
try {
|
||||
Jws<Claims> claimsJws = Jwts.parser().verifyWith(key).build().parseSignedClaims(token);
|
||||
Date expiration = claimsJws.getPayload().getExpiration();
|
||||
|
||||
return expiration != null && expiration.before(new Date());
|
||||
} catch (Exception exception) {
|
||||
log.error(exception.getMessage(), exception);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -48,3 +48,10 @@ logging:
|
|||
com.spring: debug
|
||||
org.springframework.security: debug
|
||||
|
||||
jwtToken:
|
||||
# 密钥
|
||||
secret: aVeryLongAndSecureRandomStringWithAtLeast32Characters
|
||||
# 主题
|
||||
subject: SecurityBunny
|
||||
# 过期事件 7天
|
||||
expired: 604800
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package com.spring.step2.security.config;
|
||||
|
||||
import com.spring.step2.security.service.DbUserDetailService;
|
||||
import com.spring.step2.security.service.JwtBearTokenService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@SpringBootTest
|
||||
class JwtBearTokenServiceTest {
|
||||
|
||||
private String token;
|
||||
|
||||
@Autowired
|
||||
private JwtBearTokenService jwtBearTokenService;
|
||||
|
||||
@Autowired
|
||||
private DbUserDetailService dbUserDetailService;
|
||||
|
||||
@Test
|
||||
void createToken() {
|
||||
long userId = 1944384432521744386L;
|
||||
List<String> roles = dbUserDetailService.findUserRolesByUserId(userId);
|
||||
List<String> permissions = dbUserDetailService.findPermissionByUserId(userId);
|
||||
|
||||
String token = jwtBearTokenService.createToken(userId,
|
||||
"Bunny",
|
||||
roles,
|
||||
permissions);
|
||||
this.token = token;
|
||||
System.out.println(token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUsernameFromToken() {
|
||||
createToken();
|
||||
|
||||
String username = jwtBearTokenService.getUsernameFromToken(token);
|
||||
System.out.println(username);
|
||||
|
||||
Long userId = jwtBearTokenService.getUserIdFromToken(token);
|
||||
System.out.println(userId);
|
||||
|
||||
Map<String, Object> map = jwtBearTokenService.getMapByToken(token);
|
||||
|
||||
List<?> roles = (List<?>) map.get("roles");
|
||||
System.out.println(roles);
|
||||
|
||||
// 安全转换 permissions
|
||||
List<?> permissions = (List<?>) map.get("permissions");
|
||||
System.out.println(permissions);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue