單點登錄JWT實現-實戰篇

package com.dalingjia.seckill.common.utils;


import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * JWT 工具類
 */
@Component
public class JwtTokenUtil {

protected final Logger logger = LoggerFactory.getLogger(this.getClass());
public static final String AUTH_HEADER = "Authorization";
public static final String TOKEN_HEAD = "Bearer ";

private static String secret = "seckill-3600";

private Long expiration = 1*1*60*60l;//默認存儲小時  3600秒

public Long getExpiration() {
    return expiration;
}

/**
 * 解析token
 * @param token
 * @return
 */
public static Claims parseToken(String token){
    Jws<Claims> jws = Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token);
    Claims claims = jws.getBody();
    return claims;
}

/**
 * 創建token
 * @param claims
 * @return
 */
  public static String generateToken(Map<String, Object> claims) {
    return Jwts.builder()
            .setClaims(claims)
            .signWith(SignatureAlgorithm.HS512, secret)
            .compact();
  }

}

package com.dalingjia.seckill.common.interceptor;

import com.dalingjia.seckill.common.Constants;
import com.dalingjia.seckill.common.enums.ResponseCodeEnum;
import com.dalingjia.seckill.common.exceptions.ValidateException;
import com.dalingjia.seckill.common.utils.CommonUtil;
import com.dalingjia.seckill.common.utils.JwtTokenUtil;
import com.dalingjia.seckill.entity.response.CheckAuthResponse;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import lombok.extern.log4j.Log4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by ytw83 on 2019/1/1.
 */
@Log4j
public class LoginInterceptor extends HandlerInterceptorAdapter{
private static String SUCCESS = "000000";

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String authHeader = request.getHeader(JwtTokenUtil.AUTH_HEADER);
    boolean isAjax = CommonUtil.isAjax(request);
    if (StringUtils.isEmpty(authHeader)) {
        return response(isAjax,response);
    }
    String accessToken = authHeader.substring(JwtTokenUtil.TOKEN_HEAD.length());
    if (StringUtils.isEmpty(accessToken)) {
        return response(isAjax,response);
    }

    CheckAuthResponse checkAuthResponse = validToken(accessToken);
    if (SUCCESS.equals(checkAuthResponse.getCode())) {
        return super.preHandle(request, response, handler);
    }

    if (isAjax) {
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("{\"code\":\""+checkAuthResponse.getCode()+"\"" +
                ",\"msg\":\""+checkAuthResponse.getMsg()+"\"}");
        return false;
    }
    response.sendRedirect(Constants.SSO_ACCESS_URL);
    return false;
}


public CheckAuthResponse validToken(String token) {
    CheckAuthResponse response=new CheckAuthResponse();
    try{
        beforeValidateAuth(token);

        Claims claims=JwtTokenUtil.parseToken(token);
        response.setUid(claims.get("uid").toString());
        response.setCode(ResponseCodeEnum.SUCCESS.getCode());
        response.setMsg(ResponseCodeEnum.SUCCESS.getMsg());

    }catch (ExpiredJwtException e){
        log.error("ExpiredJwtException :"+e);
        response.setCode(ResponseCodeEnum.TOKEN_EXPIRE.getCode());
        response.setMsg(ResponseCodeEnum.TOKEN_EXPIRE.getMsg());
    }catch (SignatureException e1){
        log.error("SignatureException :"+e1);
        response.setCode(ResponseCodeEnum.SIGNATURE_ERROR.getCode());
        response.setMsg(ResponseCodeEnum.SIGNATURE_ERROR.getMsg());
    }catch (Exception e){
        log.error("login occur exception :"+e);
        response.setCode(ResponseCodeEnum.SYSTEM_BUSY.getCode());
        response.setMsg(ResponseCodeEnum.SYSTEM_BUSY.getMsg());
    }finally {
        log.info("response:"+response);
    }

    return response;
}

private void beforeValidateAuth(String token){
    if(StringUtils.isEmpty(token)){
        throw new ValidateException("token信息為空");
    }
}

 private boolean response(boolean isAjax,HttpServletResponse response) throws IOException {
    if(isAjax){
        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("{\"code\":\"-1\",\"msg\":\"error\"}");
        return false;
    }
    response.sendRedirect(Constants.SSO_ACCESS_URL);
    return false;
 }
}



package com.dalingjia.seckill.common.exceptions;

import com.dalingjia.seckill.common.enums.ResponseCodeEnum;

public class ValidateException extends RuntimeException {

/**
 * versionId
 */
private static final long serialVersionUID = 7172827201346602909L;


/**
 * 返回碼
 */
private String errorCode;
/**
 * 信息
 */
private String errorMessage;

/**
 * 構造函數
 */
public ValidateException() {
    super();
}

/**
 * 構造函數
 *
 * @param errorCode
 */
public ValidateException(String errorCode) {
    super(errorCode);
    this.errorCode= ResponseCodeEnum.SYS_PARAM_NOT_RIGHT.getCode();
    this.errorMessage= ResponseCodeEnum.SYS_PARAM_NOT_RIGHT.getMsg();
}

/**
 * 構造函數
 *
 * @param cause
 */
public ValidateException(Throwable cause) {
    super(cause);
}

/**
 * 構造函數
 *
 * @param errorCode
 * @param cause
 */
public ValidateException(String errorCode, Throwable cause) {
    super(cause);
    this.errorCode = errorCode;
}

/**
 * 構造函數
 *
 * @param errorCode
 * @param message
 */
public ValidateException(String errorCode, String message) {
    super();
    this.errorCode = errorCode;
    this.errorMessage = message;
}

/**
 * 構造函數
 *
 * @param errorCode
 * @param message
 * @param cause
 */
public ValidateException(String errorCode, String message, Throwable cause) {
    super(cause);
    this.errorCode = errorCode;
    this.errorMessage = message;
}

/**
 * Getter method for property <tt>errorCode</tt>.
 *
 * @return property value of errorCode
 */
public String getErrorCode() {
    return errorCode;
}

/**
 * Setter method for property <tt>errorCode</tt>.
 *
 * @param errorCode value to be assigned to property errorCode
 */
public void setErrorCode(String errorCode) {
    this.errorCode = errorCode;
}

/**
 * Getter method for property <tt>errorMessage</tt>.
 *
 * @return property value of errorMessage
 */
public String getErrorMessage() {
    return errorMessage;
}

/**
 * Setter method for property <tt>errorMessage</tt>.
 *
 * @param errorMessage value to be assigned to property errorMessage
 */
 public void setErrorMessage(String errorMessage) {
    this.errorMessage = errorMessage;
 }

}




package com.dalingjia.seckill.common.enums;


public enum  ResponseCodeEnum {
  USERORPASSWORD_ERRROR("001001","用戶名或密碼不存在"),
  SUCCESS("000000","成功"),
  SYS_PARAM_NOT_RIGHT("001002","請求參數錯誤"),
  TOKEN_EXPIRE("001003","token過期"),
  SIGNATURE_ERROR("001004","簽名驗證失敗"),
  QUERY_DATA_NOT_EXIST("001005","請求數據不存在"),
  SYSTEM_BUSY("001099","系統繁忙,請稍候重試");

private final String code;
private final  String msg;

ResponseCodeEnum(String code, String msg) {
    this.code = code;
    this.msg = msg;
}

public String getCode() {
    return code;
}

public String getMsg() {
    return msg;
 }
}




package com.dalingjia.seckill.common.utils;

import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;

/**
 * Created by ytw83 on 2019/1/1.
 */
 public class CommonUtil {
  public static boolean isAjax(HttpServletRequest request){
    boolean isAjaxRequest = false;
    if(!StringUtils.isBlank(request.getHeader("x-requested-with")) && request.getHeader("x-requested-with").equals("XMLHttpRequest")){
        isAjaxRequest = true;
    }
    return isAjaxRequest;
 }
}




package com.dalingjia.seckill.entity.response;

import lombok.Data;

import java.io.Serializable;

@Data
public class CheckAuthResponse implements Serializable {
  private static final long serialVersionUID = -3294145027267783959L;
  private String code;
  private String msg;
  private String uid;

 @Override
 public String toString() {
    return "CheckAuthResponse{" +
            "uid='" + uid + '\'' +
            "} " + super.toString();
 }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,117評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,860評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,128評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,291評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,025評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,421評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,477評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,642評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,177評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,970評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,157評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,717評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,410評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,821評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,053評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,896評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,157評論 2 375

推薦閱讀更多精彩內容