通用框架平台,每个分支对应子通用框架平台,禁止Merge不同分支!! 分支版本区别见项目内readme.md
whycxzp
2021-01-20 129bc8f0c9bce0306aa99fafde97689f645dbbb5
finish basic jwt func
11个文件已修改
7个文件已添加
586 ■■■■■ 已修改文件
pom.xml 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/config/FilterConfig.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/config/JwtProperties.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/config/ShiroConfig.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/constant/SuperConstant.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/controller/LoginController.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/dto/Response.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/filter/JwtAuthcFilter.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/filter/JwtPermisFilter.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/filter/JwtRolesFilter.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/filter/KickedOutFilter.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/manager/JWTManager.java 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/manager/ShiroSessionManager.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/pojo/Menu.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/service/LoginService.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/whyc/util/CommonUtil.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/config/application.yml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/config/authentication.properties 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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>
src/main/java/com/whyc/config/FilterConfig.java
New file
@@ -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;
    }*/
}
src/main/java/com/whyc/config/JwtProperties.java
New file
@@ -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);
    }
}
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");
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";
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")
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;
    }
src/main/java/com/whyc/filter/JwtAuthcFilter.java
New file
@@ -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);
    }
}
src/main/java/com/whyc/filter/JwtPermisFilter.java
New file
@@ -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);
    }
}
src/main/java/com/whyc/filter/JwtRolesFilter.java
New file
@@ -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);
    }
}
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;
@@ -20,10 +26,13 @@
        HttpSession session = ((HttpServletRequest) request).getSession();
        //如果是登录,则不进行Session对比,放行
        if(!((HttpServletRequest) request).getRequestURI().contains("login")) {
            User user = ShiroUtil.getUser();
            if (user.getId() != 0) {
            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");
@@ -31,8 +40,8 @@
                    return;
                }
            }
        }
        }
        chain.doFilter(request,response);
    }
}
src/main/java/com/whyc/manager/JWTManager.java
New file
@@ -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,基于状态,用户登录状态 保存于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;
    }
}
src/main/java/com/whyc/manager/ShiroSessionManager.java
New file
@@ -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模式后,解析携带的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;
            }
        }
    }
}
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;
/**
 * 用户菜单
 */
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()){
            //每个登录的用户都有一个全局变量,里面存着对应的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());
    }
}
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);
    }
}
src/main/resources/config/application.yml
@@ -58,4 +58,5 @@
#  base-package: com.whyc.controller
knife:
  enable: true
#  enable: fase
jwt:
  hexEncodedSecretKey: perryhsu
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