基于Token登录验证与统一拦截(一个JWT的Demo)
Posted 诺浅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Token登录验证与统一拦截(一个JWT的Demo)相关的知识,希望对你有一定的参考价值。
为什么要采用Token做登录验证
上一篇文章我们讲述了基于session+cookie的登录逻辑怎么做,这种模式在服务端为单体应用的且客户端为PC端浏览器是没有问题的,但是如果服务端做集群部署的话就需要考虑的session的统一存储,且这种模式不适用与APP端,毕竟APP端不会像浏览器那样自己管理cookie.此时采用JWT就是一个很好的选择,服务端无需存储token,也就更加适用于集群部署的情况,这也就是所说的无状态。
一个JWT的Demo
引入jwt依赖包
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.7.0</version>
</dependency>
编写一个jwt工具类,该工具类主要包含了以下方法
- 使用用户名和密码生成token方法
- 解密token得到用户名方法
public class JwtUtil
// 过期时间30分钟
public static final long EXPIRE_TIME = 30 * 60 * 1000;
/**
* 校验token是否正确
*
* @param token 密钥
* @param secret 用户的密码
* @return 是否正确
*/
public static boolean verify(String token, String username, String secret)
try
// 根据密码生成JWT效验器
Algorithm algorithm = Algorithm.HMAC256(secret);
JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
// 效验TOKEN
DecodedJWT jwt = verifier.verify(token);
return true;
catch (Exception exception)
return false;
/**
* 获得token中的信息无需secret解密也能获得
*
* @return token中包含的用户名
*/
public static String getUsername(String token)
try
if (token == null)
throw new JeecgBootException("token不存在");
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("username").asString();
catch (JWTDecodeException e)
return null;
/**
* 生成签名,5min后过期
*
* @param username 用户名
* @param secret 用户的密码
* @return 加密的token
*/
public static String sign(String username, String secret)
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create().withClaim("username", username).withExpiresAt(date).sign(algorithm);
/**
* 根据request中的token获取用户账号
*
* @param request
* @return
* @throws JeecgBootException
*/
public static String getUserNameByToken(HttpServletRequest request) throws JeecgBootException
String accessToken = request.getHeader("X-Access-Token");
String username = getUsername(accessToken);
if (oConvertUtils.isEmpty(username))
throw new JeecgBootException("未获取到用户");
return username;
编写登录controller,主要用户用户登录成功后调用jwt工具类生成token返回给浏览器端的方法
@RestController
public class LoginController
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(@RequestBody SysLoginModel sysLoginModel) throws Exception
String username = sysLoginModel.getUsername();
String password = sysLoginModel.getPassword();
// 通过查询数据库校验用户名是否存在,本处模拟数据库校验
if (!"zhangsan".equals(username))
return "用户不存在";
// 校验密码是否正确
if (!"12345".equals(password))
return "密码不正确";
// 生成token
String token = JwtUtil.sign(username, password);
// 把token放到redis里面并设置过期时间
// redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
// 设置超时时间
// redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
return "登录成功,token为"+token;
接下来我们试着请求一下token
请求成功,下面来编写一个资源类
@RestController
public class HomeController
@RequestMapping("home")
public String home()
return "资源请求成功";
然后编写一个切面类来拦截未登录的请求
@Aspect
@Component
@Slf4j
public class LogAspect
// 定义切点Pointcut
@Pointcut("execution(public * com.bxoon..*.*Controller.*(..))")
public void excudeService()
@Around("excudeService()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable
long time1=System.currentTimeMillis();
HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
String requestMethod = request.getMethod();
String requestPath = request.getRequestURI().substring(request.getContextPath().length());
requestPath = filterUrl(requestPath);
log.info("拦截请求>>"+requestPath+";请求类型>>"+requestMethod);
// 实际项目中可以考虑通过配置的方式配置不需要拦截的URL LIST
if ("/login".equals(requestPath))
Object result = pjp.proceed();
long time2=System.currentTimeMillis();
log.debug("获取JSON数据 耗时:"+(time2-time1)+"ms");
return result;
try
String username = JwtUtil.getUserNameByToken(request);
catch (JeecgBootException jeecgBootException)
return jeecgBootException.getMessage();
// 用户登录成功之后考虑把用户放到session里面或者redis里面,以便controller中获取当前用户
Object result = pjp.proceed();
long time2=System.currentTimeMillis();
log.debug("获取JSON数据 耗时:"+(time2-time1)+"ms");
return result;
private String filterUrl(String requestPath)
String url = "";
if(oConvertUtils.isNotEmpty(requestPath))
url = requestPath.replace("\\\\", "/");
url = requestPath.replace("//", "/");
if(url.indexOf("//")>=0)
url = filterUrl(url);
/*if(url.startsWith("/"))
url=url.substring(1);
*/
return url;
我们试着来请求一下资源路径http://localhost:8080/home
说明我们需要设置上一步获取的token
设置了token之后资源请求成功了。
完整Demo
篇幅所限,本文只例举关键代码,完整Demo连接Github
版权说明
部分代码摘抄自JEECG,如有侵权请告知,本文删除。
以上是关于基于Token登录验证与统一拦截(一个JWT的Demo)的主要内容,如果未能解决你的问题,请参考以下文章