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的权益形成损失。