SpringBoot实现基于token的登录验证
基于token的登录验证实现原理:客户端通过用户名和密码调用登录接口,当验证数据库中存在该用户后,将用户的信息按照token的生成规则,生成一个字符串token,返回给客户端,客户端在调用其他接口的时候,需要在请求头上带上token,来验证登录信息<br /> Demo实现代码如下:<br />(因为除登录接口外,其他接口每次都需要验证token信息,所以将验证token信息的部分放在了过滤器里面)<br />————————————————<br />版权声明:本文为CSDN博主「qq_36816062」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
1.导入JWT(JSON WEB TOKEN)依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
2.Jwt工具类,包括token的生成和验证
(加密秘钥先自己随便写了一个)
package com.lzs.haiyan.utils;
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* @author : liangzesheng
* @Date : 2022-02-17
* @Description : jwt工具类
*/
@Component
public class JwtUtils {
/**
* 过期时间7200s
*/
private static final long EXPIRE_TIME=7200*1000;
/**
* 加密密钥
*/
private static final String KEY = "haiyan";
/**
* 生成token
* @param uuid 用户uuid
* @param loginnum 用户账号
* @return
*/
public static String createToken(String uuid,String loginnum){
Map<String,Object> header = new HashMap();
header.put("typ","JWT");
header.put("alg","HS256");
//setID:用户ID
//setExpiration:token过期时间 当前时间+有效时间
//setSubject:用户名
//setIssuedAt:token创建时间
//signWith:加密方式
JwtBuilder builder = Jwts.builder().setHeader(header)
.setId(uuid)
.setExpiration(new Date(System.currentTimeMillis()+EXPIRE_TIME))
.setSubject(loginnum)
.setIssuedAt(new Date())
.signWith(SignatureAlgorithm.HS256,KEY);
return builder.compact();
}
/**
* 验证token是否有效
* @param token 请求头中携带的token
* @return token验证结果 2-token过期;1-token认证通过;0-token认证失败
*/
public static int verify(String token){
Claims claims = null;
try {
//token过期后,会抛出ExpiredJwtException 异常,通过这个来判定token过期,
claims = Jwts.parser().setSigningKey(KEY).parseClaimsJws(token).getBody();
}catch (ExpiredJwtException e){
return 2;
}
//从token中获取用户id,查询该Id的用户是否存在,存在则token验证通过
String uuid = claims.getId();
User user = haiyanFilter.selectUserByUuId(uuid);
if(user != null){
return 1;
}else{
return 0;
}
return 1;
}
}
3.过滤器,实现filter接口
每有请求都要先经过过滤器再传入到接口方法
package com.lzs.haiyan.filter;
import cn.hutool.json.JSONObject;
import com.lzs.haiyan.utils.JwtUtils;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* token鉴权 过滤器
* @author : lzs
* @Date : 2022-02-17
* @Description :
*/
@Component
public class HaiyanFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
Map<String, String> map = new HashMap<>();
String url = ((HttpServletRequest) servletRequest).getRequestURI();
if (url != null) {
//注册与登录请求直接放行
if ("/user/login".equals(url)||"/user/regist".equals(url)) {
filterChain.doFilter(servletRequest, servletResponse);
return;
} else {
//其他请求验证token
String token = ((HttpServletRequest) servletRequest).getHeader("token");
if (token != null && token.length() > 0 && token.trim().length() > 0) {
//token验证结果
int verify = JwtUtils.verify(token);
if (verify != 1) {
//验证失败
if (verify == 2) {
map.put("errorMsg", "token已过期");
} else if (verify == 0) {
map.put("errorMsg", "用户信息验证失败");
}
} else if (verify == 1) {
//验证成功,放行
filterChain.doFilter(servletRequest, servletResponse);
return;
}
} else {
//token为空的返回
map.put("errorMsg", "未携带token信息");
}
}
JSONObject jsonObject = new JSONObject(map);
servletResponse.setContentType("application/json");
//设置响应的编码
servletResponse.setCharacterEncoding("utf-8");
//响应
PrintWriter pw = servletResponse.getWriter();
pw.write(jsonObject.toString());
pw.flush();
pw.close();
}
}
}