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

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云原生内存数据库 Tair,内存型 2GB
简介: 浅析单点登录(重点讲解OAuth2+JWT)

一、登录的常见方式



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对象。


8a7d0df6161a4c618d85e50001cd64fa.png


(2)有效载荷

               

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

bdec9a7996784995ac7035b9d53a9082.png

(3)签名哈希

     

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

bb315799ae59483d8671cf4069737c44.png

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)分布式访问(单点登录)


9735708f6a65469ea11debca5f43764e.png


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


(1)直接给用户名密码

(2)通用开发者key(适用于合作商之间)

(3)办法令牌


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


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


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


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


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


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
1月前
|
存储 JSON 安全
OAuth2与JWT在API安全中的角色:技术深度解析
【7月更文挑战第20天】OAuth2和JWT作为两种重要的安全协议,在API安全中发挥着不可或缺的作用。OAuth2通过提供灵活的授权框架,实现了对资源的细粒度访问控制;而JWT则通过其紧凑性和自包含性,确保了身份验证和信息传输的安全性。在实际应用中,将OAuth2和JWT结合使用,可以构建出既强大又安全的API服务,为用户提供更加安全、可靠和便捷的数字体验。
|
3月前
|
安全 Java API
深度解析 Spring Security:身份验证、授权、OAuth2 和 JWT 身份验证的完整指南
Spring Security 是一个用于保护基于 Java 的应用程序的框架。它是一个功能强大且高度可定制的身份验证和访问控制框架,可以轻松地集成到各种应用程序中,包括 Web 应用程序和 RESTful Web 服务。 Spring Security 提供了全面的安全解决方案,用于身份验证和授权,并且可以用于在 Web 和方法级别上保护应用程序。
520 0
|
3月前
|
存储 缓存 NoSQL
【带你读源码】GToken替换JWT实现SSO单点登录
今天和大家分享一下使用GoFrame的gtoken替换jwt实现sso登录的经验。
|
11月前
|
存储 JSON 安全
JWT验证用户信息功能与OAuth2协议
JWT验证用户信息功能与OAuth2协议
98 0
|
12月前
|
JSON 安全 算法
看完就懂-SpringSecurity+JWT 实现单点登录
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统
441 0
|
缓存 安全 JavaScript
Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现统一认证授权和网关鉴权
Spring Cloud Gateway + Spring Security OAuth2 + JWT 实现统一认证授权和网关鉴权
|
前端开发 安全 JavaScript
Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Vue前后端分离模式下无感知刷新实现JWT续期
Spring Cloud实战 | 最八篇:Spring Cloud +Spring Security OAuth2+ Vue前后端分离模式下无感知刷新实现JWT续期
|
存储 安全 算法
十七.SpringCloud+Security+Oauth2实现微服务授权 -非对称加密生成JWT令牌
SpringCloud+Security+Oauth2实现微服务授权 -非对称加密生成JWT令牌
|
存储 JSON 缓存
九.SpringCloud+Security+Oauth2实现微服务授权 - Oauth2&JWT的认识
SpringCloud+Security+Oauth2实现微服务授权 - Oauth2&JWT的认识
|
存储 缓存 NoSQL
Spring Cloud实战 | 最七篇:Spring Cloud Gateway+Spring Security OAuth2集成统一认证授权平台下实现注销使JWT失效方案
Spring Cloud实战 | 最七篇:Spring Cloud Gateway+Spring Security OAuth2集成统一认证授权平台下实现注销使JWT失效方案