1.令牌的生成与存储
我们原来的代码
@PostMapping("/login")
@ResponseBody
public Map<String,Object> login1(@RequestBody Map<String,Object> map,HttpServletRequest request) {
String account = (String) map.get("account");
String admin_pwd = (String) map.get("admin_pwd");
Admin login = adminService.login(account,admin_pwd);
if(login!=null){
SessionUtils.setAdmin(request,login); //增加session
map.put("code",200);
map.put("msg","登录成功");
return map;
}else{
map.put("code",600);
map.put("error","用户名密码错误");
return map;
}}
使用Token令牌
@Resourse
private RedisTemplate<String,Object> redisTemplate;
@PostMapping("/login")
@ResponseBody
public Map<String,Object> login1(@RequestBody Map<String,Object> map,HttpServletRequest request) {
String account = (String) map.get("account");
String admin_pwd = (String) map.get("admin_pwd");
Admin login = adminService.login(account,admin_pwd);
if(login!=null){
//生成Token令牌(令牌一定不能重复)
String token = UUID.randomUUID()+"";
//存到Redis数据库
redisTemplate.opsForValue().set(token,user,Duration
.ofMinutes(30L));
map.put("code",200);
map.put("msg","登录成功");
return map;
}else{
map.put("code",600);
map.put("error","用户名密码错误");
return map;
}}
2.登录成功后使用Token获取登录用户
/**
登录成功后 访问view页面的时候想要获取到当前的Token
因为view页面需要验证我们的登录信息
104成功
200登录失败
*/
@GetMapping("/view")
public Result getUserLogin(HttpServletRequest request) throws UnsupportedEncodingException{
//我们要将Token放到请求头中
String token = request.getHeader("token");
Object user = redisTemplate.opsForValue().get(token);
if(user!=null){
return new Result(user,message:"获取用户成功",code:104);}
}
return new Result(null,message:"失败没有找到token",code:200)
3.登录过滤器的Token处理
原来的代码
package com.DCWJ.springmvc.utils;
import com.DCWJ.springmvc.po.Admin;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SessionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Admin admin = SessionUtils.getAdmin(request);
if(admin == null){
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("您没有权限,请<a href='login'>登录</a>");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
使用Token后
package com.DCWJ.springmvc.utils;
import com.DCWJ.springmvc.po.Admin;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SessionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取headers中的参数
String token = request.getHeader("token");
token = token ==null ? "" : token;
//查询token在Reids中的剩余时间
Long expire = redisTemplate.getExpire(token);
if(expire <=0){
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("您没有权限,请<a href='login'>登录</a>");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
带来的问题 我们使用 redisTemplate.getExpire(token) 获取到登录时间后 我们会遇到一种情况 当这个时间只剩下1秒后,用户登录成功,但是当用户去访问另一个需要Token验证的页面,此时经过我们的过滤器会判定用户未登录,此时我们的用户需要重新登录 这给我们的用户带来很不好的体验 所以我们需要来优化一下这段代码:
第一种优化方案 :只要token时间大于0,我们使用flag=true 以后验证使用flag验证
package com.DCWJ.springmvc.utils;
import com.DCWJ.springmvc.po.Admin;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SessionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean flag = False;
//获取headers中的参数
String token = request.getHeader("token");
token = token ==null ? "" : token;
//查询token在Reids中的剩余时间
Long expire = redisTemplate.getExpire(token);
if (expire>0){
flag = true
}
if(flag=false){
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("您没有权限,请<a href='login'>登录</a>");
return false;
}
return flag;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
第二种:当大于0的时候直接重置成30分钟(推荐)
第一种优化方案 当用户登录成功后如果长时间未操作的话,则会一直的认定为用户登录的状态·,这样的用户万一多的话会占用我们的Redis内存,所以我们个他重置一下存储时间,这样就会防止这种情况
优化后的代码:
g.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SessionInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean flag = False;
//获取headers中的参数
String token = request.getHeader("token");
token = token ==null ? "" : token;
//查询token在Reids中的剩余时间
Long expire = redisTemplate.getExpire(token);
//如果时间大于0 我们就给他重置一下时间 30L是重置30分钟
redisTemplate.expire(token,30L,TimeUnit.MINUTES);
if(expire>0){
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("您没有权限,请<a href='login'>登录</a>");
return false;
}
return flag;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
4.前端存储Token
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>存储Token</title>
</head>
<body>
<script>
//永久性存储
// 第一种存储Token “{{是后端返回给前端的token}}” localStorage.setItem("key", "value");
window.localStorage.setItem("Token","{{token}}")
//读取Tonken var lastname = localStorage.getItem("key");
var item = window.localStorage.getItem("Token");
//删除数据语法 localStorage.removeItem("key");
//删除token
localStorage.removeItem("Token")
//第二种Token存储
localStorage.Token = "{{}}"
//读取
console.log(localStorage.Token)
</script>
</body>
</html>
5.在AJAX请求中携带Token
$.ajax({
url:"/view",
type:"POST",
contentType:'application/json',
dataType:'json',
data:JSON.stringify(data.field),
header:{"token":localStorage.token}
success:function(data){
layer.msg(data.msg,{time:500},
function(){
parent.layer.close(index);
});
}
});
6.使用Token改造退出功能
@Getmapping("/logout")
public Result logout(HttpServletResponse response){
String token = request.getHeader("token");
//需要在Redis里面把令牌删掉
Boolean delete = redisTemplate.delete(token);
if(delete= true){
system.out.println("删除成功")}
elif{
system.out.println("删除失败")}
}