1.令牌的生成与存储

我们原来的代码

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public Map<String,Object> login1(@RequestBody Map<String,Object> map,HttpServletRequest request) {
  4. String account = (String) map.get("account");
  5. String admin_pwd = (String) map.get("admin_pwd");
  6. Admin login = adminService.login(account,admin_pwd);
  7. if(login!=null){
  8. SessionUtils.setAdmin(request,login); //增加session
  9. map.put("code",200);
  10. map.put("msg","登录成功");
  11. return map;
  12. }else{
  13. map.put("code",600);
  14. map.put("error","用户名密码错误");
  15. return map;
  16. }}

使用Token令牌

  1. @Resourse
  2. private RedisTemplate<String,Object> redisTemplate;
  3. @PostMapping("/login")
  4. @ResponseBody
  5. public Map<String,Object> login1(@RequestBody Map<String,Object> map,HttpServletRequest request) {
  6. String account = (String) map.get("account");
  7. String admin_pwd = (String) map.get("admin_pwd");
  8. Admin login = adminService.login(account,admin_pwd);
  9. if(login!=null){
  10. //生成Token令牌(令牌一定不能重复)
  11. String token = UUID.randomUUID()+"";
  12. //存到Redis数据库
  13. redisTemplate.opsForValue().set(token,user,Duration
  14. .ofMinutes(30L));
  15. map.put("code",200);
  16. map.put("msg","登录成功");
  17. return map;
  18. }else{
  19. map.put("code",600);
  20. map.put("error","用户名密码错误");
  21. return map;
  22. }}

2.登录成功后使用Token获取登录用户

  1. /**
  2. 登录成功后 访问view页面的时候想要获取到当前的Token
  3. 因为view页面需要验证我们的登录信息
  4. 104成功
  5. 200登录失败
  6. */
  7. @GetMapping("/view")
  8. public Result getUserLogin(HttpServletRequest request) throws UnsupportedEncodingException{
  9. //我们要将Token放到请求头中
  10. String token = request.getHeader("token");
  11. Object user = redisTemplate.opsForValue().get(token);
  12. if(user!=null){
  13. return new Result(user,message:"获取用户成功",code:104);}
  14. }
  15. return new Result(null,message:"失败没有找到token"code:200)

3.登录过滤器的Token处理

原来的代码

  1. package com.DCWJ.springmvc.utils;
  2. import com.DCWJ.springmvc.po.Admin;
  3. import org.springframework.web.servlet.HandlerInterceptor;
  4. import org.springframework.web.servlet.ModelAndView;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. public class SessionInterceptor implements HandlerInterceptor {
  8. @Override
  9. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  10. Admin admin = SessionUtils.getAdmin(request);
  11. if(admin == null){
  12. response.setContentType("text/html;charset=utf-8");
  13. response.getWriter().print("您没有权限,请<a href='login'>登录</a>");
  14. return false;
  15. }
  16. return true;
  17. }
  18. @Override
  19. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  20. }
  21. @Override
  22. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  23. }
  24. }

使用Token后

  1. package com.DCWJ.springmvc.utils;
  2. import com.DCWJ.springmvc.po.Admin;
  3. import org.springframework.web.servlet.HandlerInterceptor;
  4. import org.springframework.web.servlet.ModelAndView;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. public class SessionInterceptor implements HandlerInterceptor {
  8. @Override
  9. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  10. //获取headers中的参数
  11. String token = request.getHeader("token");
  12. token = token ==null ? "" : token;
  13. //查询token在Reids中的剩余时间
  14. Long expire = redisTemplate.getExpire(token);
  15. if(expire <=0){
  16. response.setContentType("text/html;charset=utf-8");
  17. response.getWriter().print("您没有权限,请<a href='login'>登录</a>");
  18. return false;
  19. }
  20. return true;
  21. }
  22. @Override
  23. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  24. }
  25. @Override
  26. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  27. }
  28. }

带来的问题 我们使用 redisTemplate.getExpire(token) 获取到登录时间后 我们会遇到一种情况 当这个时间只剩下1秒后,用户登录成功,但是当用户去访问另一个需要Token验证的页面,此时经过我们的过滤器会判定用户未登录,此时我们的用户需要重新登录 这给我们的用户带来很不好的体验 所以我们需要来优化一下这段代码:

第一种优化方案 :只要token时间大于0,我们使用flag=true 以后验证使用flag验证

  1. package com.DCWJ.springmvc.utils;
  2. import com.DCWJ.springmvc.po.Admin;
  3. import org.springframework.web.servlet.HandlerInterceptor;
  4. import org.springframework.web.servlet.ModelAndView;
  5. import javax.servlet.http.HttpServletRequest;
  6. import javax.servlet.http.HttpServletResponse;
  7. public class SessionInterceptor implements HandlerInterceptor {
  8. @Override
  9. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  10. boolean flag = False;
  11. //获取headers中的参数
  12. String token = request.getHeader("token");
  13. token = token ==null ? "" : token;
  14. //查询token在Reids中的剩余时间
  15. Long expire = redisTemplate.getExpire(token);
  16. if (expire>0){
  17. flag = true
  18. }
  19. if(flag=false){
  20. response.setContentType("text/html;charset=utf-8");
  21. response.getWriter().print("您没有权限,请<a href='login'>登录</a>");
  22. return false;
  23. }
  24. return flag;
  25. }
  26. @Override
  27. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  28. }
  29. @Override
  30. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  31. }
  32. }

第二种:当大于0的时候直接重置成30分钟(推荐)

第一种优化方案 当用户登录成功后如果长时间未操作的话,则会一直的认定为用户登录的状态·,这样的用户万一多的话会占用我们的Redis内存,所以我们个他重置一下存储时间,这样就会防止这种情况
优化后的代码:

  1. g.springframework.web.servlet.HandlerInterceptor;
  2. import org.springframework.web.servlet.ModelAndView;
  3. import javax.servlet.http.HttpServletRequest;
  4. import javax.servlet.http.HttpServletResponse;
  5. public class SessionInterceptor implements HandlerInterceptor {
  6. @Override
  7. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  8. boolean flag = False;
  9. //获取headers中的参数
  10. String token = request.getHeader("token");
  11. token = token ==null ? "" : token;
  12. //查询token在Reids中的剩余时间
  13. Long expire = redisTemplate.getExpire(token);
  14. //如果时间大于0 我们就给他重置一下时间 30L是重置30分钟
  15. redisTemplate.expire(token,30L,TimeUnit.MINUTES);
  16. if(expire>0){
  17. response.setContentType("text/html;charset=utf-8");
  18. response.getWriter().print("您没有权限,请<a href='login'>登录</a>");
  19. return false;
  20. }
  21. return flag;
  22. }
  23. @Override
  24. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
  25. }
  26. @Override
  27. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  28. }
  29. }

4.前端存储Token

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>存储Token</title>
  6. </head>
  7. <body>
  8. <script>
  9. //永久性存储
  10. // 第一种存储Token “{{是后端返回给前端的token}}” localStorage.setItem("key", "value");
  11. window.localStorage.setItem("Token","{{token}}")
  12. //读取Tonken var lastname = localStorage.getItem("key");
  13. var item = window.localStorage.getItem("Token");
  14. //删除数据语法 localStorage.removeItem("key");
  15. //删除token
  16. localStorage.removeItem("Token")
  17. //第二种Token存储
  18. localStorage.Token = "{{}}"
  19. //读取
  20. console.log(localStorage.Token)
  21. </script>
  22. </body>
  23. </html>

5.在AJAX请求中携带Token

  1. $.ajax({
  2. url:"/view",
  3. type:"POST",
  4. contentType:'application/json',
  5. dataType:'json',
  6. data:JSON.stringify(data.field),
  7. header:{"token":localStorage.token}
  8. success:function(data){
  9. layer.msg(data.msg,{time:500},
  10. function(){
  11. parent.layer.close(index);
  12. });
  13. }
  14. });

6.使用Token改造退出功能

  1. @Getmapping("/logout")
  2. public Result logout(HttpServletResponse response){
  3. String token = request.getHeader("token");
  4. //需要在Redis里面把令牌删掉
  5. Boolean delete = redisTemplate.delete(token);
  6. if(delete= true){
  7. system.out.println("删除成功")}
  8. elif{
  9. system.out.println("删除失败")}
  10. }