JWT,oAuth和SSO的討論

JWT,oAuth和SSO的討論

背景

Single Sign On有不少成熟的方案。基於Session的服務常使用緩存Session信息在一個緩存服務上(例如redis)以實現SSO,每一個微服務使用sessionId去緩存服務上取到對應的Session信息。java

除此之外還有不基於Session的方案,相似於SAML和JWT。redis

SAML我不瞭解具體,這裏討論一下JWT。算法

oAuth和SSO

開始我把這倆搞混,覺得是一個東西。實際上oAuth是一個標準,服務方用來給第三方認證用的,好比在王者榮耀裏使用微信登錄,王者榮耀須要從微信獲取用戶的用戶名、頭像、性別等信息,使用微信登錄時,會跳轉到微信的應用/頁面中登錄,所以第三方並不知道微信的用戶名密碼。SSO是一種技術,能夠容許用戶登錄一次就能夠訪問其餘服務,經常使用戶多服務/微服務架構中,實現這種功能的技術有不少,而oAuth協議能夠用來實現SSO(把多服務中的其餘服務看作第三方)。緩存

JWT

詳細的JWT介紹參見這裏微信

一個生成的JWT 以下構成:cookie

Header.Payload.Signaturesession

Header = base64UrlEncode(header)架構

header = {"alg": "HS256", "typ": "JWT"}微服務

Payload = base64UrlEncode( 任何須要攜帶的非敏感數據 )網站

Signature = 加密算法( base64UrlEncode( header ) + "." + base64UrlEncode( payload ), 祕鑰 )

能夠這麼說: 他們都是明文(僅僅通過base64編碼),所以不該該把敏感數據放置到JWT的Payload中。通常只放一個UserName或UserId就能夠。

如何使用JWT進行SSO

在用戶第一次登陸的時候利用相似JWTProducer.createToken生成token寫入cookie(或Http Authorization Header)。以後每次請求在一個javax.servlet.Filter中去驗證token,相似JWTConsumer.verify過程,而Payload的信息能夠相似JWTConsumer.getContent取出。

package tmp.JWT;

import java.io.UnsupportedEncodingException;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;

public class JWTProducer {
    private Algorithm alg = null;

    JWTProducer() {
        try {
            alg = Algorithm.HMAC256("secret");
        } catch (IllegalArgumentException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public String createToken() {

        if (alg == null) {
            return null;
        }
        // Put Claims here
        return JWT.create().withClaim("user", "manager").withClaim("company", "SBODEMOUS").sign(alg);

    }

    public static void main(String[] args) {
        JWTProducer pro = new JWTProducer();
        System.out.println(pro.createToken());
    }
}
package tmp.JWT;

import java.io.UnsupportedEncodingException;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

public class JWTConsumer {
    private Algorithm alg = null;
    JWTVerifier verifier = null;

    JWTConsumer() {
        try {
            alg = Algorithm.HMAC256("secret");
            verifier = JWT.require(alg).build();
        } catch (IllegalArgumentException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

    public DecodedJWT verify(String token) {
        DecodedJWT jwt = verifier.verify(token);
        return jwt;
    }

    public String getContent(String token) {
        DecodedJWT jwt = this.verify(token);
        return String.format("User:[%s]\tCompany:[%s]", jwt.getClaim("user").asString(),
                jwt.getClaim("company").asString());
    }

    public static void main(String[] args) {
        final String TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjb21wYW55IjoiU0JPREVNT1VTIiwidXNlciI6Im1hbmFnZXIifQ.6iXotJonkwK_7e8bmAw_3uIqwtFTx1tVxwIwhmIBhIg";
        JWTConsumer con = new JWTConsumer();
        System.out.println(con.getContent(TOKEN));
    }
}

使用JWT注意事項

  • HTTPS和http-only的cookie
  • 強制驗證HTTP Referer以防跨站點請求僞造

CSRF

CSRF,Cross Site Request Forgery, 跨站域請求僞造

用戶訪問A網站並登錄,Cookie還在時,就去訪問B網站,而B網站能夠利用A的Cookie去訪問A的服務,從而對用戶在A的權益形成損失。

相關文章
相關標籤/搜索