您的位置:首页 > 其它

实现基于JWT的Token登录验证功能

编程100天 2019-01-22 17:38 906 查看 http://blog.51cto.com/13981400

后端实现
首先需要导入jwt的包,相关的pom.xml文件如下:

<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.5.0</version>
</dependency>

然后开始编写TokenUtil类,首先定义token的过期时间和私钥

private static final long EXPIRE_TIME = 15 * 60 * 1000;
private static final String TOKEN_SECRET = "thefirsttoken123";

实现签名方法: 这里不应该使用密码进行加密,不安全,但是是自己的小demo就这样写了。

/**
* 生成签名,15分钟过期
* @param **username**
* @param **password**
* @return
*/
public static String sign(String username, String password) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
// 私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("loginName", username)
.withClaim("pwd", password)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

实现token的检验方法:

/**
* 检验token是否正确
* @param **token**
* @return
*/
public static boolean verify(String token){
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
return true;
} catch (Exception e){
return false;
}
}

至此,工具类就编写完成啦!

登录的controller层方法 这里获取到前端发送过来的请求体,取出其中的用户名和密码,和数据库比对如果无误的话,签发token,并返回给前端。 (API响应结果还没有封装,看着有点乱,嘿嘿)

@PostMapping(value = "/login")
public Map<String, Object> login(@RequestBody SysUser sysUser){
Map<String, Object> map = new HashMap<>();
String username = sysUser.getUsername();
String password = sysUser.getPassword();
if (sysUserService.login(username, password)){
String token = TokenUtil.sign(username,password);
if (token != null){
map.put("code", "10000");
map.put("message","认证成功");
map.put("token", token);
return map;
}
}
map.put("code", "00000");
map.put("message","认证失败");
return map;
}

现在服务端给客户端签发token的功能已经差不多实现了。 那么客户端如何将token应用到以后的请求中,服务端又如何识别token呢?

实现服务端自定义拦截器

/**
* 自定义token拦截器
*/
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (request.getMethod().equals("OPTIONS")){
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
response.setCharacterEncoding("utf-8");
String token = request.getHeader("admin-token");
if (token != null){
boolean result = TokenUtil.verify(token);
if(result){
System.out.println("通过拦截器");
return true;
}
}
System.out.println("认证失败");
response.getWriter().write("50000");
return false;
}
}

TokenInterceptor实现了HandlerInterceptor接口,重写了preHandle方法,该方法是在每个请求之前触发执行,从request的头里面取出token,这里我们统一了存放token的键为admin-token,验证通过,放行,验证不通过,返回认证失败信息。
这里有一个坑,由于使用axios,每次前端发送请求,都会先发一次预请求,也就是RequestMethod为OPTIONS不是我们常见的get、post等(关于OPTIONS的解释,可以谷歌一下)。所有在这里我们需要做一次判断,如果请求方法为OPTIONS,就直接return通过。

配置拦截器
对登录界面的请求不拦截

@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
private TokenInterceptor tokenInterceptor;

public InterceptorConfig(TokenInterceptor tokenInterceptor) {
this.tokenInterceptor = tokenInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
List<String> excludePath = new ArrayList<>();
String sysUserLogin = "/api/sysUser/login";
excludePath.add(sysUserLogin);
registry.addInterceptor(tokenInterceptor).excludePathPatterns(excludePath);
}
}

服务端解析token 现在为了之后根据token去做相关的查询,我们需要对token进行解密,取出之前加密的loginName。然后就可以愉快的增删查改啦~

/**
* 从token中获取username信息
* @param **token**
* @return
*/
public static String getUserName(String token){
try {
DecodedJWT jwt = JWT.decode(token);
return jwt.getClaim("loginName").asString();
} catch (JWTDecodeException e){
e.printStackTrace();
return null;
}
}

前端实现
前端使用vue+axios,主要是实现对axios的再封装。 相关代码如下 大致逻辑就是,如果vuex中已经存在了token,那么就把它放到请求头中发往服务端。

// 创建axios实例
const service = axios.create({
baseURL: process.env.BASE_API // api 的 base_url
})

// request拦截器
service.interceptors.request.use(
config => {
if (store.getters.token) {
config.headers['admin-token'] = getToken() // 让每个请求携带自定义token
}
return config
},
error => {
// 出错
console.log(error)
Promise.reject(error)
}
)
标签:  JWT 验证功能