JWT,oAuth和SSO的讨论

JWT,oAuth和SSO的讨论

背景

Single Sign On有很多成熟的方案。基于Session的服务常使用缓存Session信息在一个缓存服务上(例如redis)以实现SSO,每个微服务使用sessionId去缓存服务上取到对应的Session信息。

除此以外还有不基于Session的方案,类似于SAML和JWT。

SAML我不了解具体,这里讨论一下JWT。

oAuth和SSO

开始我把这俩搞混,以为是一个东西。实际上oAuth是一个标准,服务方用来给第三方认证用的,比如在王者荣耀里使用微信登陆,王者荣耀需要从微信获取用户的用户名、头像、性别等信息,使用微信登陆时,会跳转到微信的应用/页面中登陆,因此第三方并不知道微信的用户名密码。SSO是一种技术,可以允许用户登陆一次就可以访问其他服务,常用户多服务/微服务架构中,实现这种功能的技术有很多,而oAuth协议可以用来实现SSO(把多服务中的其他服务看做第三方)。

JWT

详细的JWT介绍参见这里

一个生成的JWT 如下构成:

Header.Payload.Signature

Header = base64UrlEncode(header)

header =

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

posted @ 2018-06-08 16:29  开学五年级了  阅读(1084)  评论(0编辑  收藏  举报