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