目录
1.添加依赖
jwt
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.JwtUtils
这里是简单示例,因此只写了几个常用方法,包括生成token、验证token、删除token和判断token是否存在等等
@Component
public class JwtUtils {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private long expiration;
/**
* 生成token
* @param username
* @return
*/
public String generateToken(String username) {
String token = Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
// 将 Token 存储到 Redis 中
redisTemplate.opsForValue().set(username, token, expiration, TimeUnit.MILLISECONDS);
return token;
}
/**
* 验证token
* @param token
* @return
*/
public boolean validateToken(String token) {
// 从 Token 中获取用户名
String username = getUsernameFromToken(token);
// 从 Redis 中获取存储的 Token
String storedToken = redisTemplate.opsForValue().get(username);
// 判断 Redis 中存储的 Token 是否与传入的 Token 相同
return storedToken != null && storedToken.equals(token);
}
/**
* 删除token
* @param username
*/
public void removeToken(String username) {
// 从 Redis 中删除 Token
redisTemplate.delete(username);
}
/**
* 根据token获取用户信息
* @param token
* @return
*/
public String getUsernameFromToken(String token) {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return claims.getSubject();
}
/**
* 判断token是否存在
* @param username
* @return
*/
public String getTokenIfExists(String username) {
// Check if a valid token exists in Redis for the given username
String storedToken = redisTemplate.opsForValue().get(username);
// Validate the stored token
if (storedToken != null && validateToken(storedToken)) {
return storedToken;
} else {
return null;
}
}
}
3.配置文件
在application.properties或application.yml中进行redis和jwt相关配置
# JWT配置
jwt.secret=mySecretKey
jwt.expiration=86400000 # Token过期时间,单位为毫秒(默认为1天)
#注意秘钥设置的长度要大一些,我用的是512bit以上的,如下
#secret=123456sdnskdnsadnoasdsadsadasdsasadsadasdasdsadasdsadsadsadsadsadasadsadasdwdwqdwqdwqdwqdqwgewghytjgfhdfgdf
spring:
redis:
host: localhost
port: 6379
4.启动redis
这里为了方便,直接在Windows上进行启动
5.写好登录功能
这里我写一个非常简单的登录功能,主要是方便快速应用上jwt和redis
pojo
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {
private String username;
private String password;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
}
UserMapper.xml
<select id="searchUsername" resultType="com.zhan.springboot.springbootmybatis.pojo.UserInfo">
select username,password
from user
where username=#{username} And password=#{password}
</select>
UserMapper
@Mapper
public interface UserMapper {
UserInfo searchUsername(UserInfo userinfo);
}
UserService
@Repository
public interface UserService {
UserInfo searchUsername(UserInfo userInfo);
}
UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
public UserInfo searchUsername(UserInfo userInfo) {
if (userInfo == null || userInfo.getUsername() == null || userInfo.getPassword() == null) {
throw new IllegalArgumentException("Username and password must be provided");
}
// 此处添加正则表达式验证用户名格式
String usernamePattern = "^[a-zA-Z0-9_-]{3,16}$";
// 示例:允许3到16个字符,包括字母、数字、下划线和短横线
if (!userInfo.getUsername().matches(usernamePattern)) {
throw new ServiceException("Invalid username format");
}
UserInfo foundUsername = userMapper.searchUsername(userInfo);
if(foundUsername!=null){
return foundUsername;
}else{
return null;
}
}
UserController
@PostMapping("/login")
public AjaxResult login(@RequestBody UserInfo userInfo) {
try {
// 尝试在数据库中查找匹配的用户信息
UserInfo userInfo1 = userService.searchUsername(userInfo);
if (userInfo1 != null) {
// 检查用户是否已有有效的 Token
String existingToken = jwtUtils.getTokenIfExists(userInfo1.getUsername());
if (existingToken != null) {
// 如果已有有效 Token,则返回成功消息和现有 Token
return AjaxResult.success("已存在 token,登录成功", existingToken);
} else {
// 如果没有有效 Token,则生成新的 Token
String newToken = jwtUtils.generateToken(userInfo.getUsername());
return AjaxResult.success("登录成功", newToken);
}
} else {
// 如果用户不存在,返回登录失败的消息
return AjaxResult.error("登录失败");
}
} catch (ServiceException e) {
// 如果出现异常,返回异常信息给前端
return AjaxResult.error(e.getMessage());
}
}
6.测试结果
使用PostMan进行测试:
第一次登录,生成了token
检查redis中是否成功存储
第二次登录,在redis中识别出有token,不用生成新的token