| | |
| | | <modelVersion>4.0.0</modelVersion> |
| | | |
| | | <groupId>org.whyckj</groupId> |
| | | <artifactId>commonProject</artifactId> |
| | | <artifactId>commonProject-jwt</artifactId> |
| | | <version>1.0</version> |
| | | <packaging>jar</packaging> |
| | | |
| | |
| | | <!--<version>2.2.0.RELEASE</version>--> |
| | | <relativePath/> |
| | | </parent> |
| | | |
| | | <properties> |
| | | <jwt.version>3.8.1</jwt.version> |
| | | </properties> |
| | | |
| | | <dependencies> |
| | | <dependency> |
| | |
| | | <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> |
New file |
| | |
| | | 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; |
| | | }*/ |
| | | |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | @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; |
| | | } |
| | | |
| | | /** |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | 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"); |
| | |
| | | |
| | | public static String SALT ="Yin"; |
| | | |
| | | /**jwt*/ |
| | | public static final String AUTHORIZATION ="jwt"; |
| | | public static final String REFERENCED_SESSION_ID_RESOURCE ="Stateless request"; |
| | | |
| | | |
| | | |
| | | |
| | |
| | | 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; |
| | |
| | | @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") |
| | |
| | | return this; |
| | | } |
| | | |
| | | public Response<T> set(Integer code,String msg) { |
| | | this.code = code; |
| | | this.msg = msg; |
| | | return this; |
| | | } |
| | | |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
New file |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | /** |
| | | * 账号同时登录只能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)) { |
| | | //保存用户的session最新活跃时间 |
| | | request.getServletContext().setAttribute("exp_" + userName, System.currentTimeMillis()); |
| | | |
| | | System.out.println("Filter过滤器中获取到的当前Session的SessionId为:" + session.getId()); |
| | | if (!request.getServletContext().getAttribute(user.getName()).equals(session.getId())) { |
| | | if (!request.getServletContext().getAttribute(userName).equals(session.getId())) { |
| | | //如果当前Session所对应的SessionId与全局中用户对应的SessionId不一致,则清除当前Session |
| | | session.invalidate(); |
| | | response.setContentType("text/html;charset=utf-8"); |
| | |
| | | return; |
| | | } |
| | | } |
| | | } |
| | | |
| | | chain.doFilter(request,response); |
| | | } |
| | | chain.doFilter(request, response); |
| | | } |
| | | } |
New file |
| | |
| | | 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,基于状态,用户登录状态 保存于Session中,server-client是关联的 |
| | | * stateless-base: jwt,基于无状态,用户的状态 未保存在Session中,所以web请求可以由任何Server应答,发送的请求头要求包含jwt信息,以便服务器能理解状态 |
| | | * |
| | | * JWT的应用场景: |
| | | * 优点: |
| | | * 1.基于jwt的特性:由于不可篡改和有效期固定,非常适合用于一次性验证 |
| | | * 2.用户禁用cookie时,可以使用 |
| | | * 3.在分布式会话中,某些场景可以使用jwt,因为是无状态的. |
| | | * 4.前后端分离,cookie在跨域访问禁止携带,jwt适用于跨域认证 |
| | | * 缺点: |
| | | * 1.如果做会话管理: |
| | | * -无法续签,用于会话管理需要继承其他框架比如spring security auth2 jwt |
| | | * -做会话管理的话,如果cookie泄露,无法拒绝 jwt验证,因为是计算机计算校验合法性;而session的话清除session可以导致登录验证失败 |
| | | * -jwt字段长,会造成http请求开销变大 |
| | | * |
| | | * 本项目使用jwt,需要继承续签框架 |
| | | * |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class JWTManager { |
| | | |
| | | @Autowired |
| | | JwtProperties jwtProperties; |
| | | |
| | | /** |
| | | * 签发令牌: |
| | | * jwt字符串三部分: |
| | | * 1.header |
| | | * -字符串类型,一般为"JWT" |
| | | * -算法加密类型,一般为"HS256"或其他加密算法 |
| | | * 2.payload |
| | | * 常见以下四个标准字段: |
| | | * st:签发时间 |
| | | * jti:JWT唯一标识 |
| | | * signer:签发人,一般为username或者userId |
| | | * 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(); |
| | | } |
| | | |
| | | /** |
| | | * 解析令牌 |
| | | * @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和payload没有被篡改 |
| | | // 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; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | 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模式后,解析携带的jwt |
| | | String jwt = WebUtils.toHttp(request).getHeader(SuperConstant.AUTHORIZATION); |
| | | if (StringUtils.isEmpty(jwt)){ |
| | | //如果没有携带jwt,则采用cookie方式 |
| | | 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){ |
| | | //无法解密jwt,说明凭证有问题 |
| | | //e.printStackTrace(); |
| | | return null; |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import org.apache.ibatis.type.Alias; |
| | | |
| | | import java.util.ArrayList; |
| | | |
| | | /** |
| | | * 用户菜单 |
| | | */ |
| | |
| | | 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); |
| | |
| | | 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()){ |
| | | //每个登录的用户都有一个全局变量,里面存着对应的SessionId; |
| | | //同一个账号,后面登录的,会挤掉之前登录的SessionId |
| | | System.out.println("全局存储中当前SessionId为:"+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()); |
| | | //这里存储下jwt的集合,在登出的时候,去除 |
| | | 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()); |
| | | } |
| | | } |
| | |
| | | package com.whyc.util; |
| | | |
| | | import com.google.gson.Gson; |
| | | import com.whyc.pojo.User; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | # base-package: com.whyc.controller |
| | | knife: |
| | | enable: true |
| | | # enable: fase |
| | | jwt: |
| | | hexEncodedSecretKey: perryhsu |
| | |
| | | #dev接口调试时使用 |
| | | /**=anon |
| | | #/**=anon |
| | | |
| | | #静态资源不拦截 |
| | | /static/**=anon |
| | |
| | | #/WaterComm/**=rolesOr["admin","dev"] |
| | | |
| | | #其他链接是需要登录的 |
| | | #/**=authc |
| | | /**=authc-jwt |