美文网首页SSO
spring+springmvc+Interceptor+jwt

spring+springmvc+Interceptor+jwt

作者: 安琪拉_4b7e | 来源:发表于2017-11-08 08:43 被阅读313次

    在分布式环境中,如何支持PC、APP(ios、android)等多端的会话共享,这也是所有公司都需要的解决方案,用传统的session方式来解决,我想已经out了,我们是否可以找一个通用的方案,比如用传统cas来实现多系统之间的sso单点登录或使用oauth的第三方登录方案? 今天给大家简单讲解一下使用spring拦截器Interceptor机制、jwt认证方式、redis分布式缓存实现sso单点登录

    }

    publicvoid setUid(String uid) {

    this.uid = uid;

    }

    public String getToken() {

    return token;

    }

    publicvoid setToken(String token) {

    this.token = token;

    }

    publiclong getRefTime() {

    return refTime;

    }

    publicvoid setRefTime(long refTime) {

    this.refTime = refTime;

    }

    }

    public class RedisLogin implements Serializable{

    /**

    *

    */

    private static final long serialVersionUID = 8116817810829835862L;

    /**

    * 用户id

    */

    private String uid;

    /**

    * jwt生成的token信息

    */

    private String token;

    /**

    * 登录或刷新应用的时间

    */

    private long refTime;

    public RedisLogin(){

    }

    public RedisLogin(String uid, String token, long refTime){

    this.uid = uid;

    this.token = token;

    this.refTime = refTime;

    }

    public String getUid() {

    return uid;

    }

    public void setUid(String uid) {

    this.uid = uid;

    }

    public String getToken() {

    return token;

    }

    public void setToken(String token) {

    this.token = token;

    }

    public long getRefTime() {

    return refTime;

    }

    public void setRefTime(long refTime) {

    this.refTime = refTime;

    }

    }

    6. 编写LoginInterceptor.java拦截器

    Java代码

    publicclass LoginInterceptorimplements HandlerInterceptor{

    publicboolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

    throws Exception {

    PrintWriter writer =null;

    HandlerMethod method =null;

    try {

    method = (HandlerMethod) handler;

    }catch (Exception e) {

    writer = response.getWriter();

    ResponseVO responseVO = ResponseCode.buildEnumResponseVO(ResponseCode.REQUEST_URL_NOT_SERVICE,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    IsLogin isLogin = method.getMethodAnnotation(IsLogin.class);

    if(null == isLogin){

    returntrue;

    }

    response.setCharacterEncoding("utf-8");

    String token = request.getHeader("token");

    String uid = request.getHeader("uid");

    //token不存在

    if(StringUtils.isEmpty(token)) {

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TOKEN_NOT_NULL,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    if(StringUtils.isEmpty(uid)){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_NULL,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    Login login = JWT.unsign(token, Login.class);

    //解密token后的loginId与用户传来的loginId判断是否一致

    if(null == login || !StringUtils.equals(login.getUid(), uid)){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    //验证登录时间

    RedisLogin redisLogin = (RedisLogin)JedisUtils.getObject(uid);

    if(null == redisLogin){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.RESPONSE_CODE_UNLOGIN_ERROR,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    if(!StringUtils.equals(token, redisLogin.getToken())){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    //系统时间>有效期(说明已经超过有效期)

    if (System.currentTimeMillis() > redisLogin.getRefTime()) {

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TIME_EXP,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    //重新刷新有效期

    redisLogin =new RedisLogin(uid, token, System.currentTimeMillis() + 60L* 1000L* 30L);

    JedisUtils.setObject(uid , redisLogin,360000000);

    returntrue;

    }

    publicvoid postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

    ModelAndView modelAndView)throws Exception {

    }

    publicvoid afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

    throws Exception {

    }

    privatevoid responseMessage(HttpServletResponse response, PrintWriter out, ResponseVO responseVO) {

    response.setContentType("application/json; charset=utf-8");

    JSONObject result =new JSONObject();

    result.put("result", responseVO);

    out.print(result);

    out.flush();

    out.close();

    }

    }

    [java]view plaincopyprint?

    publicclass LoginInterceptorimplements HandlerInterceptor{

    publicboolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

    throws Exception {

    PrintWriter writer =null;

    HandlerMethod method =null;

    try {

    method = (HandlerMethod) handler;

    }catch (Exception e) {

    writer = response.getWriter();

    ResponseVO responseVO = ResponseCode.buildEnumResponseVO(ResponseCode.REQUEST_URL_NOT_SERVICE,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    IsLogin isLogin = method.getMethodAnnotation(IsLogin.class);

    if(null == isLogin){

    returntrue;

    }

    response.setCharacterEncoding("utf-8");

    String token = request.getHeader("token");

    String uid = request.getHeader("uid");

    //token不存在

    if(StringUtils.isEmpty(token)) {

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TOKEN_NOT_NULL,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    if(StringUtils.isEmpty(uid)){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_NULL,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    Login login = JWT.unsign(token, Login.class);

    //解密token后的loginId与用户传来的loginId判断是否一致

    if(null == login || !StringUtils.equals(login.getUid(), uid)){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    //验证登录时间

    RedisLogin redisLogin = (RedisLogin)JedisUtils.getObject(uid);

    if(null == redisLogin){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.RESPONSE_CODE_UNLOGIN_ERROR,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    if(!StringUtils.equals(token, redisLogin.getToken())){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    //系统时间>有效期(说明已经超过有效期)

    if (System.currentTimeMillis() > redisLogin.getRefTime()) {

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TIME_EXP,false);

    responseMessage(response, writer, responseVO);

    returnfalse;

    }

    //重新刷新有效期

    redisLogin =new RedisLogin(uid, token, System.currentTimeMillis() + 60L* 1000L* 30L);

    JedisUtils.setObject(uid , redisLogin,360000000);

    returntrue;

    }

    publicvoid postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

    ModelAndView modelAndView)throws Exception {

    }

    publicvoid afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

    throws Exception {

    }

    privatevoid responseMessage(HttpServletResponse response, PrintWriter out, ResponseVO responseVO) {

    response.setContentType("application/json; charset=utf-8");

    JSONObject result =new JSONObject();

    result.put("result", responseVO);

    out.print(result);

    out.flush();

    out.close();

    }

    }

    public class LoginInterceptor implements HandlerInterceptor{

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

    throws Exception {

    PrintWriter writer = null;

    HandlerMethod method = null;

    try {

    method = (HandlerMethod) handler;

    } catch (Exception e) {

    writer = response.getWriter();

    ResponseVO responseVO = ResponseCode.buildEnumResponseVO(ResponseCode.REQUEST_URL_NOT_SERVICE, false);

    responseMessage(response, writer, responseVO);

    return false;

    }

    IsLogin isLogin = method.getMethodAnnotation(IsLogin.class);

    if(null == isLogin){

    return true;

    }

    response.setCharacterEncoding("utf-8");

    String token = request.getHeader("token");

    String uid = request.getHeader("uid");

    //token不存在

    if(StringUtils.isEmpty(token)) {

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TOKEN_NOT_NULL, false);

    responseMessage(response, writer, responseVO);

    return false;

    }

    if(StringUtils.isEmpty(uid)){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_NULL, false);

    responseMessage(response, writer, responseVO);

    return false;

    }

    Login login = JWT.unsign(token, Login.class);

    //解密token后的loginId与用户传来的loginId判断是否一致

    if(null == login || !StringUtils.equals(login.getUid(), uid)){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED, false);

    responseMessage(response, writer, responseVO);

    return false;

    }

    //验证登录时间

    RedisLogin redisLogin = (RedisLogin)JedisUtils.getObject(uid);

    if(null == redisLogin){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.RESPONSE_CODE_UNLOGIN_ERROR, false);

    responseMessage(response, writer, responseVO);

    return false;

    }

    if(!StringUtils.equals(token, redisLogin.getToken())){

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.USERID_NOT_UNAUTHORIZED, false);

    responseMessage(response, writer, responseVO);

    return false;

    }

    //系统时间>有效期(说明已经超过有效期)

    if (System.currentTimeMillis() > redisLogin.getRefTime()) {

    writer = response.getWriter();

    ResponseVO responseVO = LoginResponseCode.buildEnumResponseVO(LoginResponseCode.LOGIN_TIME_EXP, false);

    responseMessage(response, writer, responseVO);

    return false;

    }

    //重新刷新有效期

    redisLogin = new RedisLogin(uid, token, System.currentTimeMillis() + 60L* 1000L* 30L);

    JedisUtils.setObject(uid , redisLogin, 360000000);

    return true;

    }

    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,

    ModelAndView modelAndView) throws Exception {

    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

    throws Exception {

    }

    private void responseMessage(HttpServletResponse response, PrintWriter out, ResponseVO responseVO) {

    response.setContentType("application/json; charset=utf-8");

    JSONObject result = new JSONObject();

    result.put("result", responseVO);

    out.print(result);

    out.flush();

    out.close();

    }

    }

    7. 定义异常的LoginResponseCode

    Java代码

    publicenum LoginResponseCode {

    USERID_NOT_NULL(3001,"用户id不能为空."),

    LOGIN_TOKEN_NOT_NULL(3002,"登录token不能为空."),

    USERID_NOT_UNAUTHORIZED(3003,"用户token或ID验证不通过"),

    RESPONSE_CODE_UNLOGIN_ERROR(421,"未登录异常"),

    LOGIN_TIME_EXP(3004,"登录时间超长,请重新登录");

    // 成员变量

    privateint code;//状态码

    private String message;//返回消息

    // 构造方法

    private LoginResponseCode(int code,String message) {

    this.code = code;

    this.message = message;

    }

    publicint getCode() {

    return code;

    }

    publicvoid setCode(int code) {

    this.code = code;

    }

    public String getMessage() {

    return message;

    }

    publicvoid setMessage(String message) {

    this.message = message;

    }

    publicstatic ResponseVO buildEnumResponseVO(LoginResponseCode responseCode, Object data) {

    returnnew ResponseVO(responseCode.getCode(),responseCode.getMessage(),data);

    }

    publicstatic Map buildReturnMap(LoginResponseCode responseCode, Object data) {

    Map map =new HashMap();

    map.put("code", responseCode.getCode());

    map.put("message", responseCode.getMessage());

    map.put("data", data);

    return map;

    }

    }

    [java]view plaincopyprint?

    publicenum LoginResponseCode {

    USERID_NOT_NULL(3001,"用户id不能为空."),

    LOGIN_TOKEN_NOT_NULL(3002,"登录token不能为空."),

    USERID_NOT_UNAUTHORIZED(3003,"用户token或ID验证不通过"),

    RESPONSE_CODE_UNLOGIN_ERROR(421,"未登录异常"),

    LOGIN_TIME_EXP(3004,"登录时间超长,请重新登录");

    // 成员变量

    privateint code;//状态码

    private String message;//返回消息

    // 构造方法

    private LoginResponseCode(int code,String message) {

    this.code = code;

    this.message = message;

    }

    publicint getCode() {

    return code;

    }

    publicvoid setCode(int code) {

    this.code = code;

    }

    public String getMessage() {

    return message;

    }

    publicvoid setMessage(String message) {

    this.message = message;

    }

    publicstatic ResponseVO buildEnumResponseVO(LoginResponseCode responseCode, Object data) {

    returnnew ResponseVO(responseCode.getCode(),responseCode.getMessage(),data);

    }

    publicstatic Map buildReturnMap(LoginResponseCode responseCode, Object data) {

    Map map =new HashMap();

    map.put("code", responseCode.getCode());

    map.put("message", responseCode.getMessage());

    map.put("data", data);

    return map;

    }

    }

    public enum LoginResponseCode {

    USERID_NOT_NULL(3001,"用户id不能为空."),

    LOGIN_TOKEN_NOT_NULL(3002,"登录token不能为空."),

    USERID_NOT_UNAUTHORIZED(3003, "用户token或ID验证不通过"),

    RESPONSE_CODE_UNLOGIN_ERROR(421, "未登录异常"),

    LOGIN_TIME_EXP(3004, "登录时间超长,请重新登录");

    // 成员变量

    private int code; //状态码

    private String message; //返回消息

    // 构造方法

    private LoginResponseCode(int code,String message) {

    this.code = code;

    this.message = message;

    }

    public int getCode() {

    return code;

    }

    public void setCode(int code) {

    this.code = code;

    }

    public String getMessage() {

    return message;

    }

    public void setMessage(String message) {

    this.message = message;

    }

    public static ResponseVO buildEnumResponseVO(LoginResponseCode responseCode, Object data) {

    return new ResponseVO(responseCode.getCode(),responseCode.getMessage(),data);

    }

    public static Map buildReturnMap(LoginResponseCode responseCode, Object data) {

    Map map = new HashMap();

    map.put("code", responseCode.getCode());

    map.put("message", responseCode.getMessage());

    map.put("data", data);

    return map;

    }

    }

    8. 编写统一sso单点登录接口:

    Java代码

    @RequestMapping(value ="/login", method = RequestMethod.POST)

    public Map login(@RequestBody JSONObject json){

    String loginName = json.optString("loginName");

    String password = json.optString("password");

    //校验用户名不能为空

    if(StringUtils.isEmpty(loginName)){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_NAME_IS_NOT_EMPTY,null);

    }

    //校验用户密码不能为空

    if(StringUtils.isEmpty(password)){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_PWD_CAN_NOT_BE_EMPTY,null);

    }

    //根据用户名查询数据库用户信息

    User user = systemService.getBaseUserByLoginName(loginName);

    //用户名或密码不正确

    if(null == user){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS,false);

    }

    boolean isValidate = systemService.validatePassword(password, user.getPassword());

    if(!isValidate){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS,false);

    }

    if(isValidate){

    //HttpSession session =request.getSession(false);

    Login login =new Login(user.getId(), user.getLoginName(), user.getPassword());

    //给用户jwt加密生成token

    String token = JWT.sign(login, 60L* 1000L* 30L);

    Map result =new HashMap();

    result.put("loginToken", token);

    result.put("userId", user.getId());

    result.put("user", user);

    //保存用户信息到session

    //session.setAttribute(user.getId() + "@@" + token, user);

    //重建用户信息

    this.rebuildLoginUser(user.getId(), token);

    return ResponseCode.buildReturnMap(ResponseCode.RESPONSE_CODE_LOGIN_SUCCESS, result);

    }

    return ResponseCode.buildReturnMap(ResponseCode.USER_LOGIN_PWD_ERROR,false);

    }

    [java]view plaincopyprint?

    @RequestMapping(value ="/login", method = RequestMethod.POST)

    public Map login(@RequestBody JSONObject json){

    String loginName = json.optString("loginName");

    String password = json.optString("password");

    //校验用户名不能为空

    if(StringUtils.isEmpty(loginName)){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_NAME_IS_NOT_EMPTY,null);

    }

    //校验用户密码不能为空

    if(StringUtils.isEmpty(password)){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_PWD_CAN_NOT_BE_EMPTY,null);

    }

    //根据用户名查询数据库用户信息

    User user = systemService.getBaseUserByLoginName(loginName);

    //用户名或密码不正确

    if(null == user){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS,false);

    }

    boolean isValidate = systemService.validatePassword(password, user.getPassword());

    if(!isValidate){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS,false);

    }

    if(isValidate){

    //HttpSession session =request.getSession(false);

    Login login =new Login(user.getId(), user.getLoginName(), user.getPassword());

    //给用户jwt加密生成token

    String token = JWT.sign(login, 60L* 1000L* 30L);

    Map result =new HashMap();

    result.put("loginToken", token);

    result.put("userId", user.getId());

    result.put("user", user);

    //保存用户信息到session

    //session.setAttribute(user.getId() + "@@" + token, user);

    //重建用户信息

    this.rebuildLoginUser(user.getId(), token);

    return ResponseCode.buildReturnMap(ResponseCode.RESPONSE_CODE_LOGIN_SUCCESS, result);

    }

    return ResponseCode.buildReturnMap(ResponseCode.USER_LOGIN_PWD_ERROR,false);

    }

    @RequestMapping(value = "/login", method = RequestMethod.POST)

    public Map login(@RequestBody JSONObject json){

    String loginName = json.optString("loginName");

    String password = json.optString("password");

    //校验用户名不能为空

    if(StringUtils.isEmpty(loginName)){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_NAME_IS_NOT_EMPTY, null);

    }

    //校验用户密码不能为空

    if(StringUtils.isEmpty(password)){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_PWD_CAN_NOT_BE_EMPTY, null);

    }

    //根据用户名查询数据库用户信息

    User user = systemService.getBaseUserByLoginName(loginName);

    //用户名或密码不正确

    if(null == user){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS, false);

    }

    boolean isValidate = systemService.validatePassword(password, user.getPassword());

    if(!isValidate){

    return MemberResponseCode.buildReturnMap(MemberResponseCode.RESPONSE_CODE_USER_VALIDATE_NO_SUCCESS, false);

    }

    if(isValidate){

    //HttpSession session =request.getSession(false);

    Login login = new Login(user.getId(), user.getLoginName(), user.getPassword());

    //给用户jwt加密生成token

    String token = JWT.sign(login, 60L* 1000L* 30L);

    Map result =new HashMap();

    result.put("loginToken", token);

    result.put("userId", user.getId());

    result.put("user", user);

    //保存用户信息到session

    //session.setAttribute(user.getId() + "@@" + token, user);

    //重建用户信息

    this.rebuildLoginUser(user.getId(), token);

    return ResponseCode.buildReturnMap(ResponseCode.RESPONSE_CODE_LOGIN_SUCCESS, result);

    }

    return ResponseCode.buildReturnMap(ResponseCode.USER_LOGIN_PWD_ERROR, false);

    }

    9. 测试sso单点登录:

    返回结果集:

    Java代码

    {

    "message":"用户登录成功",

    "data": {

    "loginToken":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDkzODA1OTU0NTksInBheWxvYWQiOiJ7XCJ1aWRcIjpcIjExXCIsXCJsb2dpbk5hbWVcIjpcImFkbWluXCIsXCJwYXNzd29yZFwiOlwiZjU0NGQxM2QyY2EwNDU5ZGQ0ZTU1NzVjNmZkYWIzMzM0MzE1MWFlZjgwYmE5ZTNiN2U1ZjM2MzJcIn0ifQ.56L60WtxHXSu9vNs6XsWy5zbmc3kP_IWG1YpReK50DM",

    "userId":"11",

    "user": {

    "QQ":"2147775633",

    "id":"11",

    "isNewRecord":false,

    "remarks":"",

    "createDate":"2017-08-08 08:08:08",

    "updateDate":"2017-10-29 11:23:50",

    "loginName":"admin",

    "no":"00012",

    "name":"admin",

    "email":"2147775633@qq.com",

    "phone":"400000000",

    "mobile":"13888888888",

    "userType":"",

    "loginIp":"0:0:0:0:0:0:0:1",

    "loginDate":"2017-10-30 10:48:06",

    "loginFlag":"1",

    "photo":"",

    "idCard":"420888888888888888",

    "oldLoginIp":"0:0:0:0:0:0:0:1",

    "oldLoginDate":"2017-10-30 10:48:06",

    "roleNames":"",

    "admin":false

    }

    },

    "code":200

    }

    愿意了解框架技术或者源码的朋友直接求求交流分享技术:3133806896

    分布式的一些解决方案,有愿意了解的朋友可以找我们团队探讨

    更多详细源码参考来源

    相关文章

      网友评论

      • ElyarAnwar:标题很霸气,排版一下更好了

      本文标题:spring+springmvc+Interceptor+jwt

      本文链接:https://www.haomeiwen.com/subject/yzqemxtx.html