Single Sign On有不少成熟的方案。基於Session的服務常使用緩存Session信息在一個緩存服務上(例如redis)以實現SSO,每一個微服務使用sessionId去緩存服務上取到對應的Session信息。java
除此之外還有不基於Session的方案,相似於SAML和JWT。redis
SAML我不瞭解具體,這裏討論一下JWT。算法
開始我把這倆搞混,覺得是一個東西。實際上oAuth是一個標準,服務方用來給第三方認證用的,好比在王者榮耀裏使用微信登錄,王者榮耀須要從微信獲取用戶的用戶名、頭像、性別等信息,使用微信登錄時,會跳轉到微信的應用/頁面中登錄,所以第三方並不知道微信的用戶名密碼。SSO是一種技術,能夠容許用戶登錄一次就能夠訪問其餘服務,經常使用戶多服務/微服務架構中,實現這種功能的技術有不少,而oAuth協議能夠用來實現SSO(把多服務中的其餘服務看作第三方)。緩存
詳細的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就能夠。
在用戶第一次登陸的時候利用相似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)); } }
CSRF,Cross Site Request Forgery, 跨站域請求僞造
用戶訪問A網站並登錄,Cookie還在時,就去訪問B網站,而B網站能夠利用A的Cookie去訪問A的服務,從而對用戶在A的權益形成損失。