中文字幕日韩精品一区二区免费_精品一区二区三区国产精品无卡在_国精品无码专区一区二区三区_国产αv三级中文在线

如何基于springSecurity的JsonWebToken的實(shí)現(xiàn)

本篇文章給大家分享的是有關(guān)如何基于springSecurity的Json Web Token的實(shí)現(xiàn),小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

目前創(chuàng)新互聯(lián)公司已為數(shù)千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站托管、服務(wù)器托管、企業(yè)網(wǎng)站設(shè)計(jì)、尼河口網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。

SecurityJwt

一個(gè)基于springSecurity的Json Web Token的實(shí)現(xiàn)

GitHub地址


提要

一、SpringSecurity

  • Spring Security,一種基于 Spring AOPServlet 過濾器的安全框架。它提供全面的安全性解決方案,同時(shí)在 Web 請(qǐng)求級(jí)和方法調(diào)用級(jí)處理身份確認(rèn)和授權(quán)。。

  • 來自Spring全家桶系列,與SpringBoot無縫銜接。為應(yīng)用系統(tǒng)提供聲明式的安全訪問控制功能,減少了為企業(yè)系統(tǒng)安全控制編寫大量重復(fù)代碼的工作。

二、JSON Web Token

  • JSON Web Token(JWT)準(zhǔn)確來說是一個(gè)規(guī)范。實(shí)際上就是一個(gè)字符串,它由三部分組成——頭部Header、載荷playload與簽名signature)。

  • 頭部Header)用于描述關(guān)于該JWT的最基本的信息,即該JWT本身的信息聲明,如簽名所用算法。

  • 載荷playload)是存放有效信息的地方。其中信息又分為三個(gè)部分——聲明部分公共部分(subject)、私有部分(claim)。

  • 簽證signature)需要base64加密后的headerbase64加密后的payload使用.連接組成的字符串,然后通過header中聲明的加密方式進(jìn)行加鹽secret組合加密構(gòu)成(注意secret是保存在服務(wù)器端的)。

  • 在分布式中直接根據(jù)token取出保存的用戶信息,以及對(duì)token可用性校驗(yàn),單點(diǎn)登錄更為簡(jiǎn)單。

  • 如何基于springSecurity的Json Web Token的實(shí)現(xiàn)

三、開發(fā)環(huán)境介紹

  • Java版本:1.8

  • 構(gòu)建工具:Gradle(目前國內(nèi)主流構(gòu)建工具依然是Maven,但是筆者用過Gradle之后就不想再用Maven了,因?yàn)?code>Gradle是真的方便很多。其倉庫結(jié)構(gòu)向下兼容Maven,也就是說可以使用任何Maven倉庫。

build.gradle文件:

plugins {
    id 'org.springframework.boot' version '2.2.0.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    id 'java'
}

group = 'org.zuoyu'
version = '1.0.0'
sourceCompatibility = '1.8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
//    這里使用的是阿里巴巴的Maven倉庫
    maven {
        url 'http://maven.aliyun.com/nexus/content/groups/public/'
    }
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'MySQL:mysql-connector-java'
    annotationProcessor 'org.projectlombok:lombok'
//    jwt依賴
    runtime('io.jsonwebtoken:jjwt-jackson:0.10.7')
    runtime('io.jsonwebtoken:jjwt-impl:0.10.7')
    compile('io.jsonwebtoken:jjwt-api:0.10.7')
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
    testImplementation 'org.springframework.security:spring-security-test'
}

test {
    useJUnitPlatform()
}

四、源碼說明

在這里只分析關(guān)鍵代碼(其中的JwtConstants.java是我自定義的final變量類)
備注:security的配置文件中,將session管理器關(guān)閉,沒有必要使用session。
1. JwtTokenUtils.java(JWT的工具類)
/**
   * 構(gòu)建JWT
   *
   * @param subject - 實(shí)體
   * @param authorities - 權(quán)限
   * @param expiration - 保留時(shí)間
   * @return - token
   */
  private static String createJwt(String subject,
      String authorities, long expiration) {
    long nowMillis = System.currentTimeMillis();
    return Jwts.builder()
        .setId(JwtConstants.createTokenId())
        .signWith(SECRET_KEY, SignatureAlgorithm.HS256)
        .setIssuer(JwtConstants.JWT_ISSUER)
        .setSubject(subject)
        .claim(JwtConstants.ROLE_CLAIMS, authorities)
        .setIssuedAt(new Date(nowMillis))
        .setNotBefore(new Date(nowMillis))
        .setExpiration(new Date(nowMillis + expiration * 1000L))
        .compact();
  }

在這里我們使用官方依賴包中的Jwts.builder()方法,創(chuàng)建一個(gè)token,其中——

  • signWith就是設(shè)置私密鑰與加密方式,SECRET_KEY為私密鑰,SignatureAlgorithm.HS256為加密方式。

  • setSubject為設(shè)置公共部分,該部分在客戶端可解密。

  • claim為設(shè)置私有部分,其參數(shù)為keyvalue形式。

  • setIssuedAttoken的簽發(fā)時(shí)間。

  • setNotBeforetoken的生效時(shí)間。

  • setExpirationtoken的失效時(shí)間。

解析token

/**
   * 解析token
   *
   * @param token -
   * @return - Claims
   */
  private static Claims parseJwt(String token) {
    return Jwts.parser()
        .setSigningKey(SECRET_KEY)
        .parseClaimsJws(token)
        .getBody();
  }

在這里重點(diǎn)在與setSigningKey,傳入我們?cè)趧?chuàng)建時(shí)候的私密鑰SECRET_KEY

還有幾個(gè)與security方便交互的方法:

 /**
   * 根據(jù)賬戶構(gòu)建token
   *
   * @param user - 賬戶
   * @return -
   */
  public static String createToken(User user, boolean isRememberMe) {
    long expiration =
        isRememberMe ? JwtConstants.EXPIRATION_REMEMBER : JwtConstants.EXPIRATION;
    String spacer = ",";
    List<string> authorities = Arrays.stream(user.getRoles().split(spacer))
        .map(role -&gt; "ROLE_" + role)
        .collect(Collectors.toList());
    return createJwt(JsonUtil.beanToJsonString(user), JsonUtil.objectToJsonString(authorities),
        expiration);
  }



  /**
   * 獲取用戶
   *
   * @param token - token
   * @return - User
   */
  public static User getUserByToken(String token) {
    String subject = parseJwt(token).getSubject();
    return JsonUtil.jsonStringToBean(subject, User.class);
  }


/**
   * 獲取用戶的權(quán)限
   * @param token - token
   * @return - 權(quán)限列表
   */
  public static Collection<!--? extends GrantedAuthority--> getAuthoritiesByToken(String token) {
    String roles = parseJwt(token).get(JwtConstants.ROLE_CLAIMS).toString();
    return JsonUtil.jsonStringToCollection(roles, SimpleGrantedAuthority.class);
  }
2. AuthenticationSuccessHandlerImpl.java(Security登錄成功后的執(zhí)行行為)
/**
 * 登錄成功的實(shí)現(xiàn).
 *
 * @author zuoyu
 **/
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {

  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
      Authentication authentication) throws IOException {
    String rememberMe = request.getParameter(JwtConstants.USER_LOGIN_REMEMBER_ME);
    boolean isRememberMe = Boolean.parseBoolean(rememberMe);
    User principal = (User) authentication.getPrincipal();
    String token = JwtTokenUtils.createToken(principal, isRememberMe);
    response.setContentType("application/json;charset=utf-8");
    response.setHeader(JwtConstants.TOKEN_HEADER, token);
    response.setStatus(HttpServletResponse.SC_OK);
    PrintWriter responseWriter = response.getWriter();
    responseWriter.write("{\"message\":\"登錄成功\"}");
    responseWriter.flush();
    responseWriter.close();
  }


}

這段代碼主要思路是——登錄成功后,在authentication中獲取已經(jīng)認(rèn)證成功的用戶信息(user),然后將該user轉(zhuǎn)換為token并返回給客戶端。其中的isRememberMe是根據(jù)是否為true給予token不同的有效時(shí)間(查看完整源代碼)。

3. JwtAuthorizationFilter.java(自定義基于JWT認(rèn)證的過濾器)
/**
 * JWT的權(quán)限過濾器.
 *
 * @author zuoyu
 * @program jwt
 * @create 2019-10-17 16:26
 **/
@Slf4j
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {

  public JwtAuthorizationFilter(AuthenticationManager authenticationManager) {
    super(authenticationManager);
  }

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
      FilterChain chain) throws IOException, ServletException {
    String token = request.getHeader(JwtConstants.TOKEN_HEADER);
    if (StringUtils.isEmpty(token)) {
      chain.doFilter(request, response);
      return;
    }
    User user = JwtTokenUtils.getUserByToken(token);
    Collection<!--? extends GrantedAuthority--> authorities = JwtTokenUtils.getAuthoritiesByToken(token);
    UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
        user, null, authorities);
    SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
    super.doFilterInternal(request, response, chain);
  }
}

這段代碼的從請(qǐng)求中獲取token,并將從token中解析出用戶信息(user)和權(quán)限信息(authorities)。并根據(jù)用戶信息(user)和權(quán)限信息(authorities)創(chuàng)建屬于security框架的權(quán)限身份(authentication),將其存入當(dāng)前的security環(huán)境。

五、使用方法

  • 項(xiàng)目啟動(dòng)后自動(dòng)建表(JPA)
  • 注冊(cè)(登錄)的賬戶名稱字段為userName
  • 注冊(cè)(登錄)的賬戶密碼字段為passWord
  • 登錄時(shí)的“記住我”字段為rememberMe

如何使用——

  1. 登錄之后,在響應(yīng)Response的頭Headers里有字段Authorization,該值就是Token

  2. 后續(xù)的訪問需在Request的頭Headers內(nèi)攜帶字段Authorization和其值,以此來表示身份。

  3. rememberMe默認(rèn)時(shí)效為一小時(shí),為true時(shí)時(shí)效7天,設(shè)置路徑在org.zuoyu.security.jwt.constants.JwtConstants.java。

  4. 測(cè)試路徑查看org.zuoyu.security.jwt.controller.AuthController.java類。

以上就是如何基于springSecurity的Json Web Token的實(shí)現(xiàn),小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

本文名稱:如何基于springSecurity的JsonWebToken的實(shí)現(xiàn)
網(wǎng)頁網(wǎng)址:http://www.rwnh.cn/article16/ghcggg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化網(wǎng)站收錄、搜索引擎優(yōu)化、網(wǎng)站設(shè)計(jì)公司、小程序開發(fā)企業(yè)建站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

成都app開發(fā)公司
托克逊县| 莱州市| 和林格尔县| 绥宁县| 尚义县| 白河县| 聂拉木县| 壶关县| 谷城县| 翼城县| 泉州市| 福建省| 钟祥市| 拜城县| 巩留县| 河源市| 明溪县| 阳山县| 积石山| 石城县| 沽源县| 洞头县| 延庆县| 碌曲县| 察哈| 清水河县| 上栗县| 岳阳县| 江门市| 印江| 阿合奇县| 新晃| 长垣县| 台前县| 斗六市| 珲春市| 芷江| 灌云县| 新邵县| 黑河市| 宿迁市|