浅析单点登录(重点讲解OAuth2+JWT)

17 篇文章 3 订阅

目录

一、登录的常见方式

        1、单一服务器模式

        2、单点登录SSO(Single Sign On)模式

二、单点登录的几种实现方式

        1、session广播机制 

        2、使用cookie + redis 

        3、令牌(使用token)

三、JWT(Json web token)

        1、JWT的介绍 

                (1)JWT头信息

                (2)有效载荷

                (3)签名哈希

        2、JWT和session比较的优缺点 

        3、JWT的使用

                (1)引入依赖 

                (2)使用JWT工具类 

四、OAuth2 

        1、开放系统间授权的几种方式 

        2、分布式访问(单点登录) 


一、登录的常见方式

        1、单一服务器模式

        使用session对象实现。

        在登录成功后,把用户数据放到session里面

session.setAttribute("user", user);

        当需要判断是否登录时,就从session里面取数据,如果可以获取到,就是已经登录了。

session.getAttribute("user");

        早期单一服务器(例如只有一台Tomcat)常用这种用户认证模式。

        缺点是 单点性能压力大,并且无法扩展。

        2、单点登录SSO(Single Sign On)模式

        在集群环境下,一个项目包括多个微服务,如果采用以往的单一服务器登录模式,那么,在一个服务器登录上后,当我们需要访问另一个微服务时,还要再次登录。

        所谓单点登录,就是在一个微服务登录后,其他微服务上都无需再次登录即可访问。

        例如,在百度百科登录账号后,当我们再访问百度文库、百度音乐、百度地图等百度服务时,都无需再次登录 ,这就是单点登录在起作用。

二、单点登录的几种实现方式

        1、session广播机制 

        当在一个微服务上登录后,登录信息保存在session中,通过session复制,将登录信息复制到其他微服务中,这就是session广播机制。通过这种机制可以实现单点登录。

        缺点是:假如微服务较多,那么session复制的次数也会增多,并且复制出的session内容都是重复的,这对资源是一种极大的浪费。所以这种方式用于早期实现单点登录,现在已经淘汰。

        2、使用cookie + redis 

        用户在任意模块登录之后,将数据保存到两个地方:

        (1)保存到Redis中

        在key中生成唯一的值(ip、用户id等);在value中保存用户数据

        (2)将Redis生成的key值保存到cookie中

        当访问项目中其他模块时,发送请求时将cookie带上,把cookie中的值到Redis中进行查询。如果能够找到,说明已经登录过;如果找不到,说明没有登录 。

        3、令牌(使用token)

        用户在任意模块登录之后,按照一定规则生成保存用户数据的字符串,并将字符串通过cookie或者通过地址栏返回。

        当用户访问其他模块时,在地址栏中带上生成的字符串。访问模块解析该字符串,根据字符串获取信息。如果能获取到用户信息,说明已经登录过;如果获取不到,说明没有登录。

三、JWT(Json web token)

        1、JWT的介绍 

        我们都知道,token是按照一定规则生成的包含用户信息的字符串。JWT就是通用的token生成规则 

        JWT生成的字符串包含三部分:

                (1)JWT头信息

                JWT头部分是一个包含JWT元数据的JSON对象。

                (2)有效载荷

                包含主题信息(用户信息) 

                (3)签名哈希

        签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。 

        2、JWT和session比较的优缺点 

 

        JWT的优点:

        (1)可扩展性好。应用程序分布式部署的情况下,session需要做多机数据共享,通常存放在Redis里面,而jwt不需要;

        (2)无状态。jwt不在服务端存储任何状态。发出请求时,总会返回带有参数的相应,不会产生附加影响;

        (3)可以降低服务器查询数据库的次数。 

 

        JWT的缺点:

         (1)安全性。由于jwt的payload是使用base64编码的,并没有加密,因此jwt中不能存储敏感数据。而session的信息是存在服务端的,相对来说更安全;

        (2)性能。jwt太长,性能开销大得多;

        (3)一次性。想要修改里面的内容,必须重新签发一个jwt。

 

 

        3、JWT的使用

                (1)引入依赖 

<!-- JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>

                (2)使用JWT工具类 

/**
 * @author helen
 * @since 2019/10/16
 */
public class JwtUtils {

    public static final long EXPIRE = 1000 * 60 * 60 * 24;
    public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";

    public static String getJwtToken(String id, String nickname){

        String JwtToken = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setHeaderParam("alg", "HS256")
                .setSubject("guli-user")
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
                .claim("id", id)
                .claim("nickname", nickname)
                .signWith(SignatureAlgorithm.HS256, APP_SECRET)
                .compact();

        return JwtToken;
    }

    /**
     * 判断token是否存在与有效
     * @param jwtToken
     * @return
     */
    public static boolean checkToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) return false;
        try {
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 判断token是否存在与有效
     * @param request
     * @return
     */
    public static boolean checkToken(HttpServletRequest request) {
        try {
            String jwtToken = request.getHeader("token");
            if(StringUtils.isEmpty(jwtToken)) return false;
            Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 根据token获取会员id
     * @param request
     * @return
     */
    public static String getMemberIdByJwtToken(HttpServletRequest request) {
        String jwtToken = request.getHeader("token");
        if(StringUtils.isEmpty(jwtToken)) return "";
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
        Claims claims = claimsJws.getBody();
        return (String)claims.get("id");
    }
}

四、OAuth2 

        OAuth2是针对特定问题的一种解决方案。 

         OAuth2主要用于解决两个问题:

        (1)开放系统授权

        (2)分布式访问(单点登录)

        1、开放系统间授权的几种方式 

                (1)直接给用户名密码
                (2)通用开发者key(适用于合作商之间)
                (3)办法令牌

                接近OAuth2的方式,需要考虑如何管理令牌、颁发令牌、吊销令牌,需要统一的协议。因此就出现了OAuth2协议

        2、分布式访问(单点登录) 

           登录成功之后,按照一定规则生成包含用户信息的字符串,然后将生成的字符串通过路径或者cookie传递。后面再发送请求时,每次都带着字符串进行发送,然后从字符串中获取用户信息。

        这就是OAuth2解决方案:令牌机制,按照一定规则生成包含用户信息的字符串。

        OAuth2并没有规定我们使用何种规则,比如我们可以使用JWT。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值