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

猜你喜欢

转载自www.cnblogs.com/qwsdcv/p/9156340.html