Browse Source

token失效问题解决

hcst_sunzhen 4 years ago
parent
commit
8b59a8c5a2

+ 3 - 0
src/main/java/cn/com/ctop/okr/config/ShiroConfig.java

@@ -2,6 +2,7 @@ package cn.com.ctop.okr.config;
 
 
 import cn.com.ctop.okr.shiro.authc.ShiroRealm;
 import cn.com.ctop.okr.shiro.authc.ShiroRealm;
 import cn.com.ctop.okr.shiro.authc.aop.JwtFilter;
 import cn.com.ctop.okr.shiro.authc.aop.JwtFilter;
+import cn.com.ctop.okr.shiro.authc.aop.ResourceCheckFilter;
 import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
 import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
 import org.apache.shiro.mgt.DefaultSubjectDAO;
 import org.apache.shiro.mgt.DefaultSubjectDAO;
 import org.apache.shiro.mgt.SecurityManager;
 import org.apache.shiro.mgt.SecurityManager;
@@ -45,6 +46,7 @@ public class ShiroConfig {
         //登录接口排除
         //登录接口排除
         //filterChainDefinitionMap.put("/sys/login", "anon");
         //filterChainDefinitionMap.put("/sys/login", "anon");
         filterChainDefinitionMap.put("/sys/wxlogin", "anon");
         filterChainDefinitionMap.put("/sys/wxlogin", "anon");
+        filterChainDefinitionMap.put("/sys/logout", "anon");
         //
         //
         ////获取加密串
         ////获取加密串
         //filterChainDefinitionMap.put("/sys/getEncryptedString", "anon");
         //filterChainDefinitionMap.put("/sys/getEncryptedString", "anon");
@@ -161,6 +163,7 @@ public class ShiroConfig {
         // 添加自己的过滤器并且取名为jwt
         // 添加自己的过滤器并且取名为jwt
         Map<String, Filter> filterMap = new HashMap<>(1);
         Map<String, Filter> filterMap = new HashMap<>(1);
         filterMap.put("jwt", new JwtFilter());
         filterMap.put("jwt", new JwtFilter());
+        //filterMap.put("check", new ResourceCheckFilter());
         shiroFilterFactoryBean.setFilters(filterMap);
         shiroFilterFactoryBean.setFilters(filterMap);
         // <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
         // <!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边
         filterChainDefinitionMap.put("/**", "jwt");
         filterChainDefinitionMap.put("/**", "jwt");

+ 21 - 8
src/main/java/cn/com/ctop/okr/controller/LoginController.java

@@ -1,11 +1,14 @@
 package cn.com.ctop.okr.controller;
 package cn.com.ctop.okr.controller;
 
 
+import cn.com.ctop.okr.constant.CommonConstant;
 import cn.com.ctop.okr.entity.QYWxUserInfo;
 import cn.com.ctop.okr.entity.QYWxUserInfo;
 import cn.com.ctop.okr.qywx.constant.QYWxConstant;
 import cn.com.ctop.okr.qywx.constant.QYWxConstant;
 import cn.com.ctop.okr.service.CorpUserInfoService;
 import cn.com.ctop.okr.service.CorpUserInfoService;
 import cn.com.ctop.okr.service.QYWxService;
 import cn.com.ctop.okr.service.QYWxService;
+import cn.com.ctop.okr.shiro.vo.DefContants;
 import cn.com.ctop.okr.utils.JwtUtil;
 import cn.com.ctop.okr.utils.JwtUtil;
 import cn.com.ctop.okr.utils.RedisUtil;
 import cn.com.ctop.okr.utils.RedisUtil;
+import cn.com.ctop.okr.utils.oConvertUtils;
 import cn.com.ctop.okr.vo.LoginUser;
 import cn.com.ctop.okr.vo.LoginUser;
 import cn.com.ctop.okr.vo.Result;
 import cn.com.ctop.okr.vo.Result;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
@@ -153,9 +156,9 @@ public class LoginController {
         String userid = user.getUserid();  //userId
         String userid = user.getUserid();  //userId
         // 生成token
         // 生成token
         String token = JwtUtil.sign(openId, userid);
         String token = JwtUtil.sign(openId, userid);
-        //redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
-        // 设置超时时间
-        //redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
+        redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);
+        //设置超时时间
+        redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME / 1000);
 
 
         // 获取用户部门信息
         // 获取用户部门信息
         JSONObject obj = new JSONObject();
         JSONObject obj = new JSONObject();
@@ -187,13 +190,23 @@ public class LoginController {
     @RequestMapping(value = "/logout")
     @RequestMapping(value = "/logout")
     public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
     public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) {
         //用户退出逻辑
         //用户退出逻辑
-        Subject subject = SecurityUtils.getSubject();
-        //LoginUser sysUser = (LoginUser) subject.getPrincipal();
-        QYWxUserInfo sysUser = (QYWxUserInfo) subject.getPrincipal();
+        //Subject subject = SecurityUtils.getSubject();
+        //QYWxUserInfo sysUser = (QYWxUserInfo) subject.getPrincipal();
 
 
-        logger.info(" 用户名:  " + sysUser.getName() + ",退出成功! ");
-        subject.logout();
+        //logger.info(" 用户名:  " + sysUser.getName() + ",退出成功! ");
+        //subject.logout();
 
 
+        //if(){
+        //
+        //}HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+
+        String token = request.getHeader(DefContants.X_ACCESS_TOKEN);
+        //String openId = JwtUtil.getUsername("");
+        //String cacheToken = String.valueOf(redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token));
+
+        if (token != null) {
+            redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
+        }
         return Result.ok("退出登录成功!");
         return Result.ok("退出登录成功!");
     }
     }
 
 

+ 7 - 4
src/main/java/cn/com/ctop/okr/shiro/authc/ShiroRealm.java

@@ -92,6 +92,7 @@ public class ShiroRealm extends AuthorizingRealm {
                 return new SimpleAuthenticationInfo(loginUser, token, getName());
                 return new SimpleAuthenticationInfo(loginUser, token, getName());
             }
             }
         }
         }
+
         return null;
         return null;
     }
     }
 
 
@@ -111,7 +112,7 @@ public class ShiroRealm extends AuthorizingRealm {
         String openId = JwtUtil.getUsername(token);  //username即为open_id
         String openId = JwtUtil.getUsername(token);  //username即为open_id
         if (openId == null) {
         if (openId == null) {
             log.error("token非法无效!");
             log.error("token非法无效!");
-            // throw new AuthenticationException("token非法无效!");
+            throw new AuthenticationException("token非法无效!");
         }
         }
         // 查询用户信息
         // 查询用户信息
         QYWxUserInfo loginUser = new QYWxUserInfo();
         QYWxUserInfo loginUser = new QYWxUserInfo();
@@ -122,9 +123,11 @@ public class ShiroRealm extends AuthorizingRealm {
         }
         }
 
 
         // 校验token是否超时失效 & 或者账号密码是否错误
         // 校验token是否超时失效 & 或者账号密码是否错误
-//        if (!jwtTokenRefresh(token, username, sysUser.getPassword())) {
-//            log.error("Token失效,请重新登录!");
-//        }
+        if (!jwtTokenRefresh(token, userInfo.getOpenId(), userInfo.getUserid())) {
+            log.error("Token失效,请重新登录!");
+            throw new AuthenticationException("Token失效,请重新登录!!");
+            //return null;
+        }
 
 
         // 判断用户状态
         // 判断用户状态
         //if (sysUser.getStatus() != 1) {
         //if (sysUser.getStatus() != 1) {

+ 43 - 3
src/main/java/cn/com/ctop/okr/shiro/authc/aop/JwtFilter.java

@@ -2,6 +2,9 @@ package cn.com.ctop.okr.shiro.authc.aop;
 
 
 import cn.com.ctop.okr.shiro.authc.JwtToken;
 import cn.com.ctop.okr.shiro.authc.JwtToken;
 import cn.com.ctop.okr.shiro.vo.DefContants;
 import cn.com.ctop.okr.shiro.vo.DefContants;
+import cn.com.ctop.okr.shiro.vo.JsonResponse;
+import cn.com.ctop.okr.shiro.vo.ResponseBean;
+import com.alibaba.fastjson.JSON;
 import lombok.extern.slf4j.Slf4j;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
 import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.HttpStatus;
@@ -11,6 +14,8 @@ import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
 
 
 /**
 /**
  * @Description: 鉴权登录拦截器
  * @Description: 鉴权登录拦截器
@@ -30,7 +35,8 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
      */
      */
     @Override
     @Override
     protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
     protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
-
+        HttpServletRequest req = (HttpServletRequest) request;
+        HttpServletResponse resp = (HttpServletResponse) response;
         boolean successful = false;
         boolean successful = false;
         try {
         try {
             successful = executeLogin(request, response);
             successful = executeLogin(request, response);
@@ -46,7 +52,6 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
      */
      */
     @Override
     @Override
     protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
     protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
-
         try {
         try {
             HttpServletRequest httpServletRequest = (HttpServletRequest) request;
             HttpServletRequest httpServletRequest = (HttpServletRequest) request;
             String token = httpServletRequest.getHeader(DefContants.X_ACCESS_TOKEN);
             String token = httpServletRequest.getHeader(DefContants.X_ACCESS_TOKEN);
@@ -56,10 +61,10 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
             // 如果没有抛出异常则代表登入成功,返回true
             // 如果没有抛出异常则代表登入成功,返回true
             return true;
             return true;
         } catch (Exception e) {
         } catch (Exception e) {
+
             return false;
             return false;
         }
         }
 
 
-
     }
     }
 
 
     /**
     /**
@@ -79,4 +84,39 @@ public class JwtFilter extends BasicHttpAuthenticationFilter {
         }
         }
         return super.preHandle(request, response);
         return super.preHandle(request, response);
     }
     }
+
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+        JsonResponse<Void> res = JsonResponse.noLogin("请先登录");
+
+        //resp.sendRedirect("http://localhost:3000/login");
+        //response.sendRedirect(state + "?code=" + code);
+        //((HttpServletResponse) response).setContentType("application/json; charset=utf-8");
+       // ResponseBean bean = new ResponseBean(500,"Token失效,请重新登录!",null);
+        //返回json
+        //((HttpServletResponse) response).getOutputStream().print("error");
+
+        out((HttpServletResponse) response, res);
+
+        return Boolean.FALSE ;
+    }
+
+
+    private void out(HttpServletResponse response, JsonResponse jsonObj){
+        PrintWriter out = null;
+        try {
+            response.setStatus(500);
+            response.setCharacterEncoding("UTF-8");
+            response.setContentType("application/json; charset=utf-8");
+            out = response.getWriter();
+            out.write(JSON.toJSONString(jsonObj));
+            //response.sendRedirect("192.168.1.94:3000/login");
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (out != null) {
+                out.close();
+            }
+        }
+    }
 }
 }

+ 58 - 0
src/main/java/cn/com/ctop/okr/shiro/authc/aop/MyMvcExceptionHandler.java

@@ -0,0 +1,58 @@
+package cn.com.ctop.okr.shiro.authc.aop;
+
+import cn.com.ctop.okr.shiro.vo.JsonResStateEnum;
+import cn.com.ctop.okr.shiro.vo.JsonResponse;
+import com.alibaba.fastjson.JSON;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authz.AuthorizationException;
+import org.apache.shiro.authz.UnauthenticatedException;
+import org.apache.shiro.authz.UnauthorizedException;
+import org.apache.shiro.session.UnknownSessionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+//@Component
+public class MyMvcExceptionHandler implements HandlerExceptionResolver {
+
+    protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Override
+    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
+
+        logger.error(ex.getMessage(), ex);
+
+        if (ex instanceof UnauthenticatedException || ex instanceof AuthenticationException || ex instanceof UnknownSessionException) {
+            return outJson(request, response, JsonResponse.noLogin("请先登录"));
+        }
+        if (ex instanceof UnauthorizedException || ex instanceof AuthorizationException) {
+            return outJson(request, response, JsonResponse.noPermission("没有访问权限"));
+        }
+        return outJson(request, response, JsonResponse.error(ex.getMessage(), JsonResStateEnum.SYSTEM_ERROR));
+    }
+
+    private ModelAndView outJson(HttpServletRequest request, HttpServletResponse response, JsonResponse res) {
+        ModelAndView mv = new ModelAndView();
+        /*  使用response返回    */
+        response.setStatus(HttpStatus.OK.value()); //设置状态码
+        response.setContentType(MediaType.APPLICATION_JSON_VALUE); //设置ContentType
+        response.setCharacterEncoding("UTF-8"); //避免乱码
+        response.setHeader("Cache-Control", "no-cache, must-revalidate");
+        try {
+            String json = JSON.toJSONString(res);
+            response.getWriter().write(json);
+        } catch (IOException e) {
+            logger.error("与客户端通讯异常:" + e.getMessage(), e);
+        }
+
+        return mv;
+    }
+}

+ 35 - 0
src/main/java/cn/com/ctop/okr/shiro/vo/JsonResStateEnum.java

@@ -0,0 +1,35 @@
+package cn.com.ctop.okr.shiro.vo;
+
+public interface JsonResStateEnum  {
+
+    /**
+     * 没有登录时的状态
+     */
+    public static final  Integer NO_LOGIN = -1;
+
+    /**
+     * 没有访问权限时的状态
+     */
+    public static final  Integer NO_PERMISSION = -2;
+
+    /**
+     * 系统错误时的错误, 不可掌控错误
+     */
+    public static final  Integer SYSTEM_ERROR = -3;
+
+    /**
+     * token验证错误
+     */
+    public static final Integer TOKEN_ERROR = -4;
+
+    /**
+     * 由用户自定义返回的错误, 受用户掌控
+     */
+    public static final  Integer USER_ERROR = 0;
+
+    /**
+     * 正常状态
+     */
+    public static final  Integer SUCCESS = 1;
+
+}

+ 106 - 0
src/main/java/cn/com/ctop/okr/shiro/vo/JsonResponse.java

@@ -0,0 +1,106 @@
+package cn.com.ctop.okr.shiro.vo;
+
+import java.io.Serializable;
+
+//@ApiModel
+public class JsonResponse<T> implements Serializable {
+
+    private static final long serialVersionUID = -7817536542662556767L;
+
+    //@ApiModelProperty("请求成功/失败标志")
+    private boolean success;
+
+    //@ApiModelProperty("状态码, -1:没有登录, -2:没有权限, -3:系统报错, 0: 后台返回错误信息, 1: 成功访问")
+    private int code;
+
+    //@ApiModelProperty("访问提示信息")
+    private String msg;
+
+    //@ApiModelProperty("后台返回数据")
+    private T data;
+
+    public JsonResponse() {
+    }
+
+    public JsonResponse(boolean success) {
+        this();
+        this.success = success;
+    }
+
+    public JsonResponse(boolean success, String msg) {
+        this(success);
+        this.msg = msg;
+    }
+
+    public JsonResponse(boolean success, String msg, int code) {
+        this(success, msg);
+        this.code = code;
+    }
+
+    public JsonResponse(boolean success, String msg, int code, T data) {
+        this(success, msg, code);
+        this.data = data;
+    }
+
+    public boolean isSuccess() {
+        return success;
+    }
+
+    public void setSuccess(boolean success) {
+        this.success = success;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public static JsonResponse<Void> SUCCESS = new JsonResponse<>(true);
+
+    public static <T> JsonResponse<T> success(T data) {
+        return new JsonResponse<>(true, null, JsonResStateEnum.SUCCESS, data);
+    }
+
+    public static <T> JsonResponse<T> success(T data, String msg) {
+        return new JsonResponse<>(true, msg, JsonResStateEnum.SUCCESS, data);
+    }
+
+    public static <T> JsonResponse<T> error(String msg) {
+        return new JsonResponse<>(false, msg, JsonResStateEnum.USER_ERROR);
+    }
+
+    public static <T> JsonResponse<T> error(String msg,  T data) {
+        return new JsonResponse<>(false, msg, JsonResStateEnum.USER_ERROR, data);
+    }
+
+    public static <T> JsonResponse<T> error(String msg, int code) {
+        return new JsonResponse<>(false, msg, code);
+    }
+
+    public static <T> JsonResponse<T> noLogin(String msg) {
+        return new JsonResponse<>(false, msg, JsonResStateEnum.NO_LOGIN);
+    }
+
+    public static <T> JsonResponse<T> noPermission(String msg) {
+        return new JsonResponse<>(false, msg, JsonResStateEnum.NO_PERMISSION);
+    }
+}

+ 7 - 1
src/main/java/cn/com/ctop/okr/utils/DateUtils.java

@@ -1367,7 +1367,13 @@ public class DateUtils extends PropertyEditorSupport {
     }
     }
 
 
     public static void main(String[] args) {
     public static void main(String[] args) {
-        System.out.println(stampToDate(1593740000L * 1000));
+        //System.out.println(stampToDate(1593740000L * 1000));
+        Integer pageSize = 20;
+
+        Integer TotalPage = (20-1)/pageSize + 1;
+
+        System.out.println(TotalPage);
+
     }
     }
 }
 }
 
 

+ 3 - 1
src/main/java/cn/com/ctop/okr/utils/JwtUtil.java

@@ -20,7 +20,9 @@ public class JwtUtil {
     /**
     /**
      * 过期时间30分钟
      * 过期时间30分钟
      */
      */
-    public static final long EXPIRE_TIME = 30 * 60 * 1000;
+    public static final long EXPIRE_TIME = 2 * 24 * 60 * 60 * 1000;
+    //public static final long EXPIRE_TIME = 10 * 1000;
+
 
 
     /**
     /**
      * 校验token是否正确
      * 校验token是否正确

+ 18 - 4
src/main/resources/application.yml

@@ -84,13 +84,27 @@ spring:
           username: hcst
           username: hcst
           password: test@20190531
           password: test@20190531
 
 
-
           driver-class-name: com.mysql.jdbc.Driver
           driver-class-name: com.mysql.jdbc.Driver
 
 
-  #redis 配置
+
+  #redis dev 配置
+#  redis:
+#    database: 0
+#    host: 127.0.0.1
+#    lettuce:
+#      pool:
+#        max-active: 8   #最大连接数据库连接数,设 0 为没有限制
+#        max-idle: 8     #最大等待连接中的数量,设 0 为没有限制
+#        max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
+#        min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
+#      shutdown-timeout: 100ms
+#    port: 6379
+#
+
+  #redis prod 配置
   redis:
   redis:
     database: 0
     database: 0
-    host: 127.0.0.1
+    host: 172.30.0.17
     lettuce:
     lettuce:
       pool:
       pool:
         max-active: 8   #最大连接数据库连接数,设 0 为没有限制
         max-active: 8   #最大连接数据库连接数,设 0 为没有限制
@@ -98,7 +112,7 @@ spring:
         max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
         max-wait: -1ms  #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
         min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
         min-idle: 0     #最小等待连接中的数量,设 0 为没有限制
       shutdown-timeout: 100ms
       shutdown-timeout: 100ms
-    #password: foobared
+    password: foobared
     port: 6379
     port: 6379