1. 程式人生 > 其它 >上雲安全,有我守護。初觀HaaS100中AliOS Things系統安全能力

上雲安全,有我守護。初觀HaaS100中AliOS Things系統安全能力

為什麼使用JWT?

隨著技術的發展,分散式web應用的普及,通過session管理使用者登入狀態成本越來越高,因此慢慢發展成為token的方式做登入身份校驗,然後通過token去取redis中的快取的使用者資訊,隨著之後jwt的出現,校驗方式更加簡單便捷化,無需通過redis快取,而是直接根據token取出儲存的使用者資訊,以及對token可用性校驗,單點登入更為簡單。這裡還有一個線上的的JWT生成器

什麼時候你應該用JSON Web Tokens

下列場景中使用JSON Web Token是很有用的:

  • Authorization(授權) : 這是使用JWT的最常見場景。一旦使用者登入,後續每個請求都將包含JWT,允許使用者訪問該令牌允許的路由、服務和資源。單點登入是現在廣泛使用的JWT的一個特性,因為它的開銷很小,並且可以輕鬆地跨域使用。
  • Information Exchange(資訊交換) : 對於安全的在各方之間傳輸資訊而言,JSON Web Tokens無疑是一種很好的方式。因為JWTs可以被簽名,例如,用公鑰/私鑰對,你可以確定傳送人就是它們所說的那個人。另外,由於簽名是使用頭和有效負載計算的,您還可以驗證內容沒有被篡改。

JSON Web Token的結構是什麼樣的

JSON Web Token由三部分組成,它們之間用圓點(.)連線。這三部分分別是:

  • Header
  • Payload
  • Signature

因此,一個典型的JWT看起來是這個樣子的:

xxxxx.yyyyy.zzzzz

接下來,具體看一下每一部分:

Header

header典型的由兩部分組成:token的型別(“JWT”)和演算法名稱(比如:HMAC SHA256或者RSA等等)。

例如:

然後,用Base64對這個JSON編碼就得到JWT的第一部分

Payload

JWT的第二部分是payload,它包含宣告(要求)。宣告是關於實體(通常是使用者)和其他資料的宣告。宣告有三種類型: registered, public 和 private。

  • Registered claims : 這裡有一組預定義的宣告,它們不是強制的,但是推薦。比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等。
  • Public claims : 可以隨意定義。
  • Private claims : 用於在同意使用它們的各方之間共享資訊,並且不是註冊的或公開的宣告。

下面是一個例子:

對payload進行Base64編碼就得到JWT的第二部分

注意,不要在JWT的payload或header中放置敏感資訊,除非它們是加密的。

Signature

為了得到簽名部分,你必須有編碼過的header、編碼過的payload、一個祕鑰,簽名演算法是header中指定的那個,然對它們簽名即可。

例如:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

簽名是用於驗證訊息在傳遞過程中有沒有被更改,並且,對於使用私鑰簽名的token,它還可以驗證JWT的傳送方是否為它所稱的傳送方。

看一張官網的圖就明白了:

JSON Web Tokens是如何工作的

  1. 應用(或者客戶端)想授權伺服器請求授權。例如,如果用授權碼流程的話,就是/oauth/authorize
  2. 當授權被許可以後,授權伺服器返回一個access token給應用
  3. 應用使用access token訪問受保護的資源(比如:API)

使用JWT核心程式碼:
maven依賴:
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
     <version>3.2.0</version>
</dependency>
<dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.7.0</version>
</dependency>

JWT工具類:
用於生成Token,和Token驗證

public class JwtUtils {
    /**
     * 簽發JWT
     * 
     * @param id
     * @param subject   可以是JSON資料 儘可能少
     * @param ttlMillis
     * @return String
     *
     */
    public static String createJWT(String id, String subject, long ttlMillis) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        SecretKey secretKey = generalKey();
        JwtBuilder builder = Jwts.builder().setId(id).setSubject(subject) // 主題
                .setIssuer("user") // 簽發者
                .setIssuedAt(now) // 簽發時間
                .signWith(signatureAlgorithm, secretKey); // 簽名演算法以及密匙
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            builder.setExpiration(expDate); // 過期時間
        }
        return builder.compact();
    }

    /**
     * 驗證JWT
     * 
     * @param jwtStr
     * @return
     */
    public static CheckResult validateJWT(String jwtStr) {
        CheckResult checkResult = new CheckResult();
        Claims claims = null;
        try {
            claims = parseJWT(jwtStr);
            checkResult.setSuccess(true);
            checkResult.setClaims(claims);
        } catch (ExpiredJwtException e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_EXPIRE);
            checkResult.setSuccess(false);
        } catch (SignatureException e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        } catch (Exception e) {
            checkResult.setErrCode(SystemConstant.JWT_ERRCODE_FAIL);
            checkResult.setSuccess(false);
        }
        return checkResult;
    }

    public static SecretKey generalKey() {
        byte[] encodedKey = Base64.decode(SystemConstant.JWT_SECERT);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
        return key;
    }

    /**
     * 
     * 解析JWT字串
     * 
     * @param jwt
     * @return
     * @throws Exception
     */
    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
    }
}

如何使用?
程式碼例項:

public class LoginController {
    @Autowired
    UserRepository userRepository;
    

    @RequestMapping(value="login",method = RequestMethod.POST)
    public ReturnVo login(String username, String password,HttpServletResponse
            response) {
        User user =  userRepository.findByUsername(username);
        if(user!=null){
            if(user.getPassword().equals(password)){
                //把token返回給客戶端-->客戶端儲存至cookie-->客戶端每次請求附帶cookie引數
                String JWT = JwtUtils.createJWT("1", username, SystemConstant.JWT_TTL);
                return ReturnVo.ok(JWT);
            }else{
                return ReturnVo.error();
            }
        }else{
            return ReturnVo.error();
        }
    }

@RequestMapping(value="description",method = RequestMethod.POST) public ReturnVo description(String username) { User user = userRepository.findByUsername(username); return ReturnVo.ok(user.getDescription()); } }
轉載:https://www.cnblogs.com/aaron911/p/11300062.html