From 129bc8f0c9bce0306aa99fafde97689f645dbbb5 Mon Sep 17 00:00:00 2001
From: whycxzp <perryhsu@163.com>
Date: 星期三, 20 一月 2021 09:39:30 +0800
Subject: [PATCH] finish basic jwt func

---
 src/main/java/com/whyc/util/CommonUtil.java             |    6 
 src/main/java/com/whyc/manager/ShiroSessionManager.java |   46 ++++
 src/main/java/com/whyc/service/LoginService.java        |   66 ++++++
 src/main/java/com/whyc/controller/LoginController.java  |   33 +-
 src/main/java/com/whyc/dto/Response.java                |    6 
 src/main/java/com/whyc/pojo/Menu.java                   |    2 
 src/main/java/com/whyc/filter/JwtAuthcFilter.java       |   65 ++++++
 src/main/java/com/whyc/filter/JwtRolesFilter.java       |   41 ++++
 pom.xml                                                 |   17 +
 src/main/java/com/whyc/config/ShiroConfig.java          |   27 ++
 src/main/resources/config/authentication.properties     |    4 
 src/main/java/com/whyc/filter/KickedOutFilter.java      |   23 +
 src/main/java/com/whyc/config/FilterConfig.java         |   22 ++
 src/main/java/com/whyc/config/JwtProperties.java        |   26 ++
 src/main/java/com/whyc/filter/JwtPermisFilter.java      |   42 ++++
 src/main/resources/config/application.yml               |    3 
 src/main/java/com/whyc/constant/SuperConstant.java      |    4 
 src/main/java/com/whyc/manager/JWTManager.java          |  159 +++++++++++++++
 18 files changed, 561 insertions(+), 31 deletions(-)

diff --git a/pom.xml b/pom.xml
index ae68f78..356eb31 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>org.whyckj</groupId>
-    <artifactId>commonProject</artifactId>
+    <artifactId>commonProject-jwt</artifactId>
     <version>1.0</version>
     <packaging>jar</packaging>
 
@@ -16,6 +16,10 @@
         <!--<version>2.2.0.RELEASE</version>-->
         <relativePath/>
     </parent>
+
+    <properties>
+        <jwt.version>3.8.1</jwt.version>
+    </properties>
 
     <dependencies>
         <dependency>
@@ -123,6 +127,17 @@
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
         </dependency>
+        <!--JWT-->
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>${jwt.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.1</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/src/main/java/com/whyc/config/FilterConfig.java b/src/main/java/com/whyc/config/FilterConfig.java
new file mode 100644
index 0000000..62e0b88
--- /dev/null
+++ b/src/main/java/com/whyc/config/FilterConfig.java
@@ -0,0 +1,22 @@
+package com.whyc.config;
+
+import com.whyc.filter.KickedOutFilter;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.filter.DelegatingFilterProxy;
+
+import javax.servlet.Filter;
+
+@Configuration
+public class FilterConfig {
+
+    /*@Bean
+    public FilterRegistrationBean Filter02(){
+        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
+        registrationBean.setFilter(new KickedOutFilter());
+        registrationBean.setOrder(2);
+        return registrationBean;
+    }*/
+
+}
diff --git a/src/main/java/com/whyc/config/JwtProperties.java b/src/main/java/com/whyc/config/JwtProperties.java
new file mode 100644
index 0000000..00e2460
--- /dev/null
+++ b/src/main/java/com/whyc/config/JwtProperties.java
@@ -0,0 +1,26 @@
+package com.whyc.config;
+
+import lombok.extern.log4j.Log4j;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * jwt閰嶇疆鏂囦欢
+ */
+@Slf4j
+@Component
+@ConfigurationProperties(prefix = "jwt")
+public class JwtProperties {
+
+    private String hexEncodedSecretKey;
+
+    public String getHexEncodedSecretKey() {
+        return hexEncodedSecretKey;
+    }
+
+    public void setHexEncodedSecretKey(String hexEncodedSecretKey) {
+        this.hexEncodedSecretKey = hexEncodedSecretKey;
+        log.info("JWT閰嶇疆淇℃伅key:{}",hexEncodedSecretKey);
+    }
+}
diff --git a/src/main/java/com/whyc/config/ShiroConfig.java b/src/main/java/com/whyc/config/ShiroConfig.java
index 402477a..4d88761 100644
--- a/src/main/java/com/whyc/config/ShiroConfig.java
+++ b/src/main/java/com/whyc/config/ShiroConfig.java
@@ -1,7 +1,10 @@
 package com.whyc.config;
 
+import com.whyc.filter.JwtAuthcFilter;
 import com.whyc.filter.KickedOutFilter;
 import com.whyc.filter.RolesOrAuthorizationFilter;
+import com.whyc.manager.JWTManager;
+import com.whyc.manager.ShiroSessionManager;
 import com.whyc.properties.PropertiesUtil;
 import com.whyc.realm.CustomRealm;
 import lombok.extern.log4j.Log4j;
@@ -9,8 +12,10 @@
 import org.apache.shiro.spring.LifecycleBeanPostProcessor;
 import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
 import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
+import org.apache.shiro.util.ThreadContext;
 import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
 import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
+import org.apache.shiro.web.servlet.SimpleCookie;
 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
@@ -33,12 +38,31 @@
     @Autowired
     CustomRealm customRealm;
 
+    @Autowired
+    JWTManager jwtManager;
+
     /**鏉冮檺绠$悊鍣�*/
     @Bean(name = "securityManager")
     public DefaultWebSecurityManager defaultWebSecurityManager(){
         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
         securityManager.setRealm(customRealm);
+        securityManager.setSessionManager(shiroSessionManager());
         return securityManager;
+    }
+
+    @Bean(name = "sessionManager")
+    public ShiroSessionManager shiroSessionManager(){
+        ShiroSessionManager shiroSessionManager = new ShiroSessionManager();
+        shiroSessionManager.setSessionIdCookie(simpleCookie());
+        return shiroSessionManager;
+    }
+
+    /**Cookie鎸囧畾Session鍚嶇О*/
+    @Bean(name = "sessionIdCookie")
+    public SimpleCookie simpleCookie(){
+        SimpleCookie simpleCookie = new SimpleCookie();
+        simpleCookie.setName("shiroSession");
+        return simpleCookie;
     }
 
     /**
@@ -83,6 +107,7 @@
     private Map<String, Filter> filters(){
         HashMap<String, Filter> map = new HashMap<>();
         map.put("rolesOr",new RolesOrAuthorizationFilter());
+        map.put("authc-jwt",new JwtAuthcFilter(jwtManager));
         return map;
     }
 
@@ -92,8 +117,8 @@
     public ShiroFilterFactoryBean shiroFilterFactoryBean(){
         ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
         //娉ㄥ叆鏂板畾涔夌殑杩囨护鍣�
-        shiroFilter.setFilters(filters());
         shiroFilter.setSecurityManager(defaultWebSecurityManager());
+        shiroFilter.setFilters(filters());
         shiroFilter.setFilterChainDefinitionMap(filterChainDefinition());
         shiroFilter.setLoginUrl("/login.html");
         //shiroFilter.setLoginUrl("/index.html#login");
diff --git a/src/main/java/com/whyc/constant/SuperConstant.java b/src/main/java/com/whyc/constant/SuperConstant.java
index 59ff5de..1ef1b12 100644
--- a/src/main/java/com/whyc/constant/SuperConstant.java
+++ b/src/main/java/com/whyc/constant/SuperConstant.java
@@ -13,6 +13,10 @@
 
     public static String SALT ="Yin";
 
+    /**jwt*/
+    public static final String AUTHORIZATION ="jwt";
+    public static final String REFERENCED_SESSION_ID_RESOURCE ="Stateless request";
+
 
 
 
diff --git a/src/main/java/com/whyc/controller/LoginController.java b/src/main/java/com/whyc/controller/LoginController.java
index 35670f0..072e987 100644
--- a/src/main/java/com/whyc/controller/LoginController.java
+++ b/src/main/java/com/whyc/controller/LoginController.java
@@ -11,6 +11,7 @@
 import springfox.documentation.annotations.ApiIgnore;
 
 import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -23,30 +24,26 @@
     @Autowired
     private LoginService service;
 
-    @PostMapping("login")
-    @ApiOperation(value ="鐧诲綍")
+    @Deprecated
+    //@PostMapping("login")
+    //@ApiOperation(value ="鐧诲綍")
+    @ApiIgnore
     public Response login(@RequestParam String userName, String password,HttpServletRequest request){
         return service.login(userName,password,request);
     }
 
-    @PostMapping("logout")
-    @ApiOperation(value ="閫�鍑虹櫥褰�")
-    public void logout(){
-        service.logout();
+    /**閲囧彇鐨勬槸JWT鏂瑰紡鐧诲綍,涓婇潰鐨勬櫘閫氱櫥褰曞純鐢�*/
+    @PostMapping("login")
+    @ApiOperation(value ="鐧诲綍")
+    public Response login4Jwt(@RequestParam String userName, String password,HttpServletRequest request){
+        return service.login4Jwt(userName,password,request);
     }
 
-    /**鎷︽埅鐧诲綍*//*
-    @GetMapping("/")
-    @ApiIgnore
-    public ModelAndView toLoginHtml(HttpServletRequest request, HttpServletResponse response,ModelAndView view) throws ServletException, IOException {
-        //request.getRequestDispatcher("login.html").forward(request,response);
-        System.out.println("杞彂鍟�...");
-        //response.setContentType("text/html;charset=utf-8");
-        //response.sendRedirect("http://localhost:8090/login.html");
-        //response.sendRedirect("/login.html");
-        view.setViewName("login");
-        return view;
-    }*/
+    @PostMapping("logout")
+    @ApiOperation(value ="閫�鍑虹櫥褰�")
+    public void logout(ServletRequest request){
+        service.logout(request);
+    }
 
     /**鎷︽埅鐧诲綍*/
     @GetMapping("unauthorized")
diff --git a/src/main/java/com/whyc/dto/Response.java b/src/main/java/com/whyc/dto/Response.java
index 6bdf1bf..c088fab 100644
--- a/src/main/java/com/whyc/dto/Response.java
+++ b/src/main/java/com/whyc/dto/Response.java
@@ -46,6 +46,12 @@
         return this;
     }
 
+    public Response<T> set(Integer code,String msg) {
+        this.code = code;
+        this.msg = msg;
+        return this;
+    }
+
     public Integer getCode() {
         return code;
     }
diff --git a/src/main/java/com/whyc/filter/JwtAuthcFilter.java b/src/main/java/com/whyc/filter/JwtAuthcFilter.java
new file mode 100644
index 0000000..527fa3a
--- /dev/null
+++ b/src/main/java/com/whyc/filter/JwtAuthcFilter.java
@@ -0,0 +1,65 @@
+package com.whyc.filter;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import com.whyc.constant.SuperConstant;
+import com.whyc.dto.Response;
+import com.whyc.manager.JWTManager;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
+import org.apache.shiro.web.util.WebUtils;
+import org.json.JSONObject;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/**
+ * 鐧诲綍楠岃瘉杩囨护鍣�
+ */
+@Slf4j
+public class JwtAuthcFilter extends FormAuthenticationFilter {
+    private JWTManager jwtManager;
+
+    public JwtAuthcFilter(JWTManager jwtManager) {
+        this.jwtManager = jwtManager;
+    }
+
+    @Override
+    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+        log.debug("鏄惁鍏佽璁块棶 鏂规硶鎵ц浜�");
+        String jwt = WebUtils.toHttp(request).getHeader(SuperConstant.AUTHORIZATION);
+        if(!StringUtils.isEmpty(jwt)) {
+            boolean verifyToken = jwtManager.verifyToken(jwt,request);
+            if (verifyToken) {
+                return super.isAccessAllowed(request, response, mappedValue);
+            } else {
+                return false;
+            }
+        }
+        //涓嶅瓨鍦ㄥ垯璧板師濮嬫牎楠�
+        return super.isAccessAllowed(request, response, mappedValue);
+    }
+
+    /**
+     * 璁块棶鎷掔粷鏃惰皟鐢�
+     * @param request
+     * @param response
+     * @return
+     * @throws Exception
+     */
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
+        log.debug("璁块棶琚嫆缁濅簡");
+        String jwt = WebUtils.toHttp(request).getHeader(SuperConstant.AUTHORIZATION);
+        if(!StringUtils.isEmpty(jwt)){
+            Response myResponse = new Response().set(1,"鏈櫥褰曟垨鑰呯櫥褰曡秴鏃�");
+            response.setCharacterEncoding("UTF-8");
+            response.setContentType("application/json;charset=utf-8");
+            Gson gson = new Gson();
+            response.getWriter().write(gson.toJson(myResponse));
+            return false;
+        }
+        return super.onAccessDenied(request, response);
+    }
+}
diff --git a/src/main/java/com/whyc/filter/JwtPermisFilter.java b/src/main/java/com/whyc/filter/JwtPermisFilter.java
new file mode 100644
index 0000000..ed25ae8
--- /dev/null
+++ b/src/main/java/com/whyc/filter/JwtPermisFilter.java
@@ -0,0 +1,42 @@
+package com.whyc.filter;
+
+import com.google.gson.Gson;
+import com.whyc.constant.SuperConstant;
+import com.whyc.dto.Response;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
+import org.apache.shiro.web.util.WebUtils;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+
+/**
+ * 鍙互鍦ㄥ畾鍒跺寲璧勬簮鏉冮檺琚嫆缁濇椂鐨勮繑鍥�,鏆備笉鐢�
+ */
+@Deprecated
+@Slf4j
+public class JwtPermisFilter extends PermissionsAuthorizationFilter {
+    /**
+     * 璁块棶鎷掔粷鏃惰皟鐢�
+     * @param request
+     * @param response
+     * @return
+     * @throws Exception
+     */
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
+        log.debug("璁块棶琚嫆缁濅簡");
+        String jwt = WebUtils.toHttp(request).getHeader(SuperConstant.AUTHORIZATION);
+        if(!StringUtils.isEmpty(jwt)){
+            Response myResponse = new Response().set(1,"鏈櫥褰�");
+            response.setCharacterEncoding("UTF-8");
+            response.setContentType("application/json;charset=utf-8");
+            Gson gson = new Gson();
+            response.getWriter().write(gson.toJson(myResponse));
+            return false;
+        }
+        return super.onAccessDenied(request, response);
+    }
+}
diff --git a/src/main/java/com/whyc/filter/JwtRolesFilter.java b/src/main/java/com/whyc/filter/JwtRolesFilter.java
new file mode 100644
index 0000000..b66b434
--- /dev/null
+++ b/src/main/java/com/whyc/filter/JwtRolesFilter.java
@@ -0,0 +1,41 @@
+package com.whyc.filter;
+
+import com.google.gson.Gson;
+import com.whyc.constant.SuperConstant;
+import com.whyc.dto.Response;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
+import org.apache.shiro.web.util.WebUtils;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.IOException;
+
+/**
+ * 鍙互鍦ㄥ畾鍒跺寲瑙掕壊鏉冮檺琚嫆缁濇椂鐨勮繑鍥�,鏆備笉鐢�
+ */
+@Deprecated
+@Slf4j
+public class JwtRolesFilter extends RolesAuthorizationFilter {
+    /**
+     * 璁块棶鎷掔粷鏃惰皟鐢�
+     * @param request
+     * @param response
+     * @return
+     */
+    @Override
+    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
+        log.debug("璁块棶琚嫆缁濅簡");
+        String jwt = WebUtils.toHttp(request).getHeader(SuperConstant.AUTHORIZATION);
+        if(!StringUtils.isEmpty(jwt)){
+            Response myResponse = new Response().set(1,"鏈櫥褰�");
+            response.setCharacterEncoding("UTF-8");
+            response.setContentType("application/json;charset=utf-8");
+            Gson gson = new Gson();
+            response.getWriter().write(gson.toJson(myResponse));
+            return false;
+        }
+        return super.onAccessDenied(request, response);
+    }
+}
diff --git a/src/main/java/com/whyc/filter/KickedOutFilter.java b/src/main/java/com/whyc/filter/KickedOutFilter.java
index 858a11d..8ad316f 100644
--- a/src/main/java/com/whyc/filter/KickedOutFilter.java
+++ b/src/main/java/com/whyc/filter/KickedOutFilter.java
@@ -2,6 +2,12 @@
 
 import com.whyc.pojo.User;
 import com.whyc.util.ShiroUtil;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.util.StringUtils;
 
 import javax.servlet.*;
 import javax.servlet.annotation.WebFilter;
@@ -12,18 +18,21 @@
 /**
  * 璐﹀彿鍚屾椂鐧诲綍鍙兘1涓�
  */
-@WebFilter(urlPatterns = "/*",filterName = "kickedOutFilter")
+@WebFilter(urlPatterns = "/*", filterName = "kickedOutFilter")
 public class KickedOutFilter implements Filter {
 
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
         HttpSession session = ((HttpServletRequest) request).getSession();
         //濡傛灉鏄櫥褰�,鍒欎笉杩涜Session瀵规瘮,鏀捐
-        if(!((HttpServletRequest) request).getRequestURI().contains("login")) {
-            User user = ShiroUtil.getUser();
-            if (user.getId() != 0) {
+        if (!((HttpServletRequest) request).getRequestURI().contains("login")) {
+            String userName = (String) request.getServletContext().getAttribute(session.getId());
+            if (!StringUtils.isEmpty(userName)) {
+                //淇濆瓨鐢ㄦ埛鐨剆ession鏈�鏂版椿璺冩椂闂�
+                request.getServletContext().setAttribute("exp_" + userName, System.currentTimeMillis());
+
                 System.out.println("Filter杩囨护鍣ㄤ腑鑾峰彇鍒扮殑褰撳墠Session鐨凷essionId涓�:" + session.getId());
-                if (!request.getServletContext().getAttribute(user.getName()).equals(session.getId())) {
+                if (!request.getServletContext().getAttribute(userName).equals(session.getId())) {
                     //濡傛灉褰撳墠Session鎵�瀵瑰簲鐨凷essionId涓庡叏灞�涓敤鎴峰搴旂殑SessionId涓嶄竴鑷�,鍒欐竻闄ゅ綋鍓峉ession
                     session.invalidate();
                     response.setContentType("text/html;charset=utf-8");
@@ -31,8 +40,8 @@
                     return;
                 }
             }
-        }
 
-        chain.doFilter(request,response);
+        }
+        chain.doFilter(request, response);
     }
 }
diff --git a/src/main/java/com/whyc/manager/JWTManager.java b/src/main/java/com/whyc/manager/JWTManager.java
new file mode 100644
index 0000000..abf3365
--- /dev/null
+++ b/src/main/java/com/whyc/manager/JWTManager.java
@@ -0,0 +1,159 @@
+package com.whyc.manager;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.TokenExpiredException;
+import com.whyc.config.JwtProperties;
+import com.whyc.pojo.User;
+import com.whyc.util.CommonUtil;
+import com.whyc.util.EncodesUtil;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.*;
+
+/**
+ * JWT 绠$悊:
+ *  state-base: session,鍩轰簬鐘舵��,鐢ㄦ埛鐧诲綍鐘舵�� 淇濆瓨浜嶴ession涓�,server-client鏄叧鑱旂殑
+ *  stateless-base: jwt,鍩轰簬鏃犵姸鎬�,鐢ㄦ埛鐨勭姸鎬� 鏈繚瀛樺湪Session涓�,鎵�浠eb璇锋眰鍙互鐢变换浣昐erver搴旂瓟,鍙戦�佺殑璇锋眰澶磋姹傚寘鍚玧wt淇℃伅,浠ヤ究鏈嶅姟鍣ㄨ兘鐞嗚В鐘舵��
+ *
+ * JWT鐨勫簲鐢ㄥ満鏅�:
+ * 浼樼偣:
+ *  1.鍩轰簬jwt鐨勭壒鎬�:鐢变簬涓嶅彲绡℃敼鍜屾湁鏁堟湡鍥哄畾,闈炲父閫傚悎鐢ㄤ簬涓�娆℃�ч獙璇�
+ *  2.鐢ㄦ埛绂佺敤cookie鏃�,鍙互浣跨敤
+ *  3.鍦ㄥ垎甯冨紡浼氳瘽涓�,鏌愪簺鍦烘櫙鍙互浣跨敤jwt,鍥犱负鏄棤鐘舵�佺殑.
+ *  4.鍓嶅悗绔垎绂�,cookie鍦ㄨ法鍩熻闂姝㈡惡甯�,jwt閫傜敤浜庤法鍩熻璇�
+ * 缂虹偣:
+ *  1.濡傛灉鍋氫細璇濈鐞�:
+ *  -鏃犳硶缁,鐢ㄤ簬浼氳瘽绠$悊闇�瑕佺户鎵垮叾浠栨鏋舵瘮濡俿pring security auth2 jwt
+ *  -鍋氫細璇濈鐞嗙殑璇�,濡傛灉cookie娉勯湶,鏃犳硶鎷掔粷 jwt楠岃瘉,鍥犱负鏄绠楁満璁$畻鏍¢獙鍚堟硶鎬�;鑰宻ession鐨勮瘽娓呴櫎session鍙互瀵艰嚧鐧诲綍楠岃瘉澶辫触
+ *  -jwt瀛楁闀�,浼氶�犳垚http璇锋眰寮�閿�鍙樺ぇ
+ *
+ * 鏈」鐩娇鐢╦wt,闇�瑕佺户鎵跨画绛炬鏋�
+ *
+ */
+@Component
+@Slf4j
+public class JWTManager {
+
+    @Autowired
+    JwtProperties jwtProperties;
+
+    /**
+     * 绛惧彂浠ょ墝:
+     *  jwt瀛楃涓蹭笁閮ㄥ垎:
+     *  1.header
+     *      -瀛楃涓茬被鍨�,涓�鑸负"JWT"
+     *      -绠楁硶鍔犲瘑绫诲瀷,涓�鑸负"HS256"鎴栧叾浠栧姞瀵嗙畻娉�
+     *  2.payload
+     *      甯歌浠ヤ笅鍥涗釜鏍囧噯瀛楁:
+     *      st:绛惧彂鏃堕棿
+     *      jti:JWT鍞竴鏍囪瘑
+     *      signer:绛惧彂浜�,涓�鑸负username鎴栬�卽serId
+     *      exp:杩囨湡鏃堕棿
+     *  3.signature
+     *      瀵�1鍜�2杩涜header涓殑绠楁硶鍔犲叆绛捐瘉绉橀挜,闃叉浠ょ墝琚鏀�
+     * @param signer 绛惧彂浜�
+     * @param ttlMillis 浠ょ墝鏈夋晥鏃堕暱
+     * @param sessionId 鍞竴鏍囪瘑
+     * @param claims 澹版槑map,鍙惡甯﹀叾浠栬嚜瀹氫箟淇℃伅
+     * @return
+     */
+    public String issueToken(String signer, long ttlMillis, String sessionId, Map<String,Object> claims){
+        if(claims==null){
+            claims = new HashMap<>();
+        }
+        long mowMillis = System.currentTimeMillis();
+        //绛惧悕绉橀挜
+        String hexEncodedSecretKey = EncodesUtil.encodeHex(this.jwtProperties.getHexEncodedSecretKey().getBytes());
+
+        JwtBuilder jwtBuilder = Jwts.builder()
+                .setClaims(claims)
+                //鍞竴鏍囪瘑
+                .setId(sessionId)
+                //绛惧彂鏃堕棿
+                .setIssuedAt(new Date(mowMillis))
+                //绛惧彂浜�
+                .setSubject(signer)
+                //绛捐瘉绉橀挜
+                .signWith(SignatureAlgorithm.HS256, hexEncodedSecretKey.getBytes());
+        if(ttlMillis>=0) {
+            //杩囨湡鏃堕棿
+            long expMillis = mowMillis + ttlMillis;
+            Date exp = new Date(expMillis);
+            jwtBuilder.setExpiration(exp);
+        }
+
+        return jwtBuilder.compact();
+    }
+
+    /**
+     * 瑙f瀽浠ょ墝
+     * @param jwt 浠ょ墝
+     * @return
+     */
+    public Claims decodeToken(String jwt){
+        String encodeHex = EncodesUtil.encodeHex(jwtProperties.getHexEncodedSecretKey().getBytes());
+        //寰楀埌DefaultJwtParser
+        return Jwts.parser()
+                //璁剧疆绛惧悕鐨勭閽�
+                .setSigningKey(encodeHex.getBytes())
+                //鍙互鍋忕Щ24h,杩囨湡1澶╁唴鍙互鑾峰彇.瓒呰繃1澶╀細鐧诲綍澶辫触
+                .setAllowedClockSkewSeconds(86400000)
+                //璁剧疆闇�瑕佽В鏋愮殑jwt
+                .parseClaimsJws(jwt)
+                .getBody();
+
+    }
+
+    /**
+     * 鍒ゆ柇浠ょ墝鏄惁鍚堟硶
+     * @param jwt 浠ょ墝
+     * @return
+     */
+    public boolean verifyToken(String jwt, ServletRequest request){
+        boolean res = false;
+        String encodeHex = EncodesUtil.encodeHex(jwtProperties.getHexEncodedSecretKey().getBytes());
+        //杩欐槸瀹樻柟鐨勬牎楠岃鍒�,鍙互鑷畾涔�
+        Algorithm algorithm = Algorithm.HMAC256(encodeHex);
+        JWTVerifier jwtVerifier = JWT.require(algorithm).build();
+        try {
+            //鏍¢獙涓嶉�氳繃浼氭姏鍑哄紓甯�
+            //鍒ゆ柇鍚堟硶鐨勬爣鍑�:1.header鍜宲ayload娌℃湁琚鏀�
+            //             2.娌℃湁杩囨湡
+            //澧炲姞:棣栧厛鍒ゆ柇jwt鏄惁鏈夋晥,鍦ㄥ唴瀛樹腑瀛樺湪,瀹為檯涓婂凡缁忓皢jwt鐘舵�佸寲浜�
+            List jwts = (List) request.getServletContext().getAttribute("jwts");
+            if(jwts!=null && jwts.contains(jwt)) {
+                jwtVerifier.verify(jwt);
+                res = true;
+            }
+        }catch (TokenExpiredException expiredException){
+            log.error("expiredException");
+            //瀵逛簬绌洪棽鏃堕棿灏忎簬30鍒嗛挓鐨�,杩囨湡浜嗕篃鍙互閫氳繃鏍¢獙,鍙樼浉缁
+            Claims claims = decodeToken(jwt);
+            String userJson = (String) claims.get("user");
+            User user = CommonUtil.toUser(userJson);
+            Date date = new Date();
+            //System.out.println("褰撳墠鏃堕棿:"+date);
+            Date date1 = new Date((Long) request.getServletContext().getAttribute("exp_" + user.getName()));
+            //System.out.println("鏈�鏂版椿璺冩椂闂�:"+date1);
+            if (System.currentTimeMillis()-(Long) request.getServletContext().getAttribute("exp_" + user.getName())  <= 180000) {
+                //System.out.println("璺濈鏈�鏂版椿璺冩椂闂村皬浜�3鍒嗛挓");
+                res = true;
+            }
+        }catch (Exception e){
+            log.error("exception");
+        }
+        return res;
+    }
+
+}
diff --git a/src/main/java/com/whyc/manager/ShiroSessionManager.java b/src/main/java/com/whyc/manager/ShiroSessionManager.java
new file mode 100644
index 0000000..146ab88
--- /dev/null
+++ b/src/main/java/com/whyc/manager/ShiroSessionManager.java
@@ -0,0 +1,46 @@
+package com.whyc.manager;
+
+import com.whyc.constant.SuperConstant;
+import io.jsonwebtoken.Claims;
+import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
+import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
+import org.apache.shiro.web.util.WebUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import java.io.Serializable;
+
+public class ShiroSessionManager extends DefaultWebSessionManager {
+
+    public ShiroSessionManager() {
+    }
+
+    @Autowired
+    JWTManager jwtManager;
+
+    @Override
+    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
+        //鏀瑰彉session妯″紡鍚�,瑙f瀽鎼哄甫鐨刯wt
+        String jwt = WebUtils.toHttp(request).getHeader(SuperConstant.AUTHORIZATION);
+        if (StringUtils.isEmpty(jwt)){
+            //濡傛灉娌℃湁鎼哄甫jwt,鍒欓噰鐢╟ookie鏂瑰紡
+            return super.getSessionId(request,response);
+        }else{
+            //璁剧疆request灞炴�т负鏃犵姸鎬�,SessionId
+            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,SuperConstant.REFERENCED_SESSION_ID_RESOURCE);
+            try {
+                Claims claims = jwtManager.decodeToken(jwt);
+                String sessionId = (String) claims.get("jti");
+                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
+                request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
+                return sessionId;
+            }catch (Exception e){
+                //鏃犳硶瑙e瘑jwt,璇存槑鍑瘉鏈夐棶棰�
+                //e.printStackTrace();
+                return null;
+            }
+        }
+    }
+}
diff --git a/src/main/java/com/whyc/pojo/Menu.java b/src/main/java/com/whyc/pojo/Menu.java
index d79b537..cc1bd4f 100644
--- a/src/main/java/com/whyc/pojo/Menu.java
+++ b/src/main/java/com/whyc/pojo/Menu.java
@@ -3,6 +3,8 @@
 import com.baomidou.mybatisplus.annotation.TableName;
 import org.apache.ibatis.type.Alias;
 
+import java.util.ArrayList;
+
 /**
  * 鐢ㄦ埛鑿滃崟
  */
diff --git a/src/main/java/com/whyc/service/LoginService.java b/src/main/java/com/whyc/service/LoginService.java
index 0805e52..5cca6f3 100644
--- a/src/main/java/com/whyc/service/LoginService.java
+++ b/src/main/java/com/whyc/service/LoginService.java
@@ -1,17 +1,33 @@
 package com.whyc.service;
 
+import com.google.gson.Gson;
+import com.whyc.constant.SuperConstant;
 import com.whyc.dto.Response;
+import com.whyc.manager.JWTManager;
+import com.whyc.pojo.User;
 import com.whyc.util.ShiroUtil;
+import net.minidev.json.JSONObject;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.UsernamePasswordToken;
 import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
+import org.apache.shiro.web.util.WebUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.ServletRequest;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 @Service
 public class LoginService {
+
+    @Autowired
+    JWTManager jwtManager;
 
     public Response login(String userName, String password, HttpServletRequest request) {
         UsernamePasswordToken userToken = new UsernamePasswordToken(userName, password);
@@ -31,8 +47,56 @@
         return new Response<>().set(1,false);
     }
 
-    public void logout() {
+    public Response login4Jwt(String userName, String password, HttpServletRequest request) {
+        UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
+        Subject subject = SecurityUtils.getSubject();
+        String jwt =null;
+        try {
+            subject.login(token);
+            //鐧诲綍鍚庨鍙戜护鐗�
+            String shiroSessionId = ShiroUtil.getShiroSessionId();
+            User user = ShiroUtil.getUser();
+            Map<String, Object> claims = new HashMap<>();
+            claims.put("user", new Gson().toJson(user));
+            //jwt = jwtManager.issueToken("system", subject.getSession().getTimeout(), shiroSessionId, claims);
+            jwt = jwtManager.issueToken("system", 10000, shiroSessionId, claims);
+        }catch (Exception e){
+            return new Response<>().set(1,false);
+        }
+        if (subject.isAuthenticated()){
+            //姣忎釜鐧诲綍鐨勭敤鎴烽兘鏈変竴涓叏灞�鍙橀噺,閲岄潰瀛樼潃瀵瑰簲鐨凷essionId;
+            //鍚屼竴涓处鍙�,鍚庨潰鐧诲綍鐨�,浼氭尋鎺変箣鍓嶇櫥褰曠殑SessionId
+            System.out.println("鍏ㄥ眬瀛樺偍涓綋鍓峉essionId涓�:"+request.getSession().getId());
+            request.getServletContext().setAttribute(userName,request.getSession().getId());
+            //鏍规嵁Context瀛樺偍鐨勫搴旂殑鍊�,鑾峰彇褰撳墠鐨勭敤鎴峰悕
+            request.getServletContext().setAttribute(request.getSession().getId(),userName);
+            //鐧诲綍鐨勬椂鍊欏垵濮嬪寲 娲昏穬鏍囪瘑
+            request.getServletContext().setAttribute("exp_" + userName, System.currentTimeMillis());
+            //杩欓噷瀛樺偍涓媕wt鐨勯泦鍚�,鍦ㄧ櫥鍑虹殑鏃跺��,鍘婚櫎
+            List<String> jwts =null;
+            if(request.getServletContext().getAttribute("jwts")==null){
+                jwts = new ArrayList<>();
+            }else {
+                jwts = (List) request.getServletContext().getAttribute("jwts");
+            }
+            jwts.add(jwt);
+            request.getServletContext().setAttribute("jwts",jwts);
+
+            return new Response<>().set(1,true,jwt);
+        }
+        return new Response<>().set(1,false);
+    }
+
+    public void logout(ServletRequest request) {
+        //娓呴櫎Subject涓粦瀹氱殑淇℃伅
         Subject subject = SecurityUtils.getSubject();
         subject.logout();
+        //娓呴櫎jwts涓殑jwt淇℃伅
+        String jwt = WebUtils.toHttp(request).getHeader(SuperConstant.AUTHORIZATION);
+        List jwts = (List) request.getServletContext().getAttribute("jwts");
+        jwts.remove(jwt);
+        request.getServletContext().setAttribute("jwts",jwts);
+        //娓呴櫎Context涓繚瀛樼殑SessionId鍊�
+        request.getServletContext().removeAttribute(((HttpServletRequest)request).getSession().getId());
     }
 }
diff --git a/src/main/java/com/whyc/util/CommonUtil.java b/src/main/java/com/whyc/util/CommonUtil.java
index 587cf36..3b3d062 100644
--- a/src/main/java/com/whyc/util/CommonUtil.java
+++ b/src/main/java/com/whyc/util/CommonUtil.java
@@ -1,5 +1,6 @@
 package com.whyc.util;
 
+import com.google.gson.Gson;
 import com.whyc.pojo.User;
 
 import javax.servlet.http.HttpServletRequest;
@@ -13,4 +14,9 @@
     public static User getUser(HttpServletRequest request) {
         return (User) request.getSession().getAttribute("user");
     }
+
+    public static User toUser(String json){
+        Gson gson = new Gson();
+        return gson.fromJson(json,User.class);
+    }
 }
diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml
index 1369392..0d58efb 100644
--- a/src/main/resources/config/application.yml
+++ b/src/main/resources/config/application.yml
@@ -58,4 +58,5 @@
 #  base-package: com.whyc.controller
 knife:
   enable: true
-#  enable: fase
+jwt:
+  hexEncodedSecretKey: perryhsu
diff --git a/src/main/resources/config/authentication.properties b/src/main/resources/config/authentication.properties
index 317c088..5667e71 100644
--- a/src/main/resources/config/authentication.properties
+++ b/src/main/resources/config/authentication.properties
@@ -1,5 +1,5 @@
 #dev鎺ュ彛璋冭瘯鏃朵娇鐢�
-/**=anon
+#/**=anon
 
 #闈欐�佽祫婧愪笉鎷︽埅
 /static/**=anon
@@ -24,4 +24,4 @@
 #/WaterComm/**=rolesOr["admin","dev"]
 
 #鍏朵粬閾炬帴鏄渶瑕佺櫥褰曠殑
-#/**=authc
+/**=authc-jwt

--
Gitblit v1.9.1