likes
comments
collection
share

聊天的时候被问到,“单设备/多设备/单点登录的架构如何设计?”

作者站长头像
站长
· 阅读数 5

1.单设备登录

先来讲讲单设备登录的问题,会有人把单点登录和单设备登录混为一谈的,注意这两者完全不一样

聊天的时候被问到,“单设备/多设备/单点登录的架构如何设计?”

单设备登录到底应该怎么实现呢?

通过Username作为key,确保一个用户只能够对应一个Token,以此来实现用户的单设备登录

注意一个点,我们是可以在Token里面保存一些数据的,比如username

举个例子;

你在PC端登录成功了,此时后端在Redis里面存储了 username:token1 的键值对,在你的浏览器本地保存了Token

此时你在手机端进行登录,此时后端又会将你此次登录生成的Token放入到Redis里面

即将原来的username:token1改为了username:token2,然后你再回到PC端进行操作

当PC端进行操作时,带上了在PC端登录的时候保存的Token1去Redis里面进行验证

此时该username对应的Token已经是Token2了,不是Token1了,就会验证失败要求你重新登录

2.多设备登录

多设备登录,即你即可以在电脑端登录该网站,也可以在手机端或者ipad端登陆该网站,实现“多地”登陆

聊天的时候被问到,“单设备/多设备/单点登录的架构如何设计?”

在这里我们可以这样设计,对每个端我都生成不一样的Token,这些Token都对应着用户信息

在每个端访问的时候,带上各自独立的Token,以此实现多设备登录

大家觉得这样的设计方案合理吗?有什么问题吗?

如果Redis存储的时候是这样设计话,那是不是意味着我可以多台电脑同时登录同一个网站的同一个账号了?

那是不是我有多台手机我也能在多台手机中同时登录同一个网站的同一个账号,这样合理不?

3.多设备登录 --- 同种设备不允许多地登陆

针对上面的第二种实现方式的问题,我们考虑到同种设备多次登录的情况,我们希望的是同种设备只能有一部进行登录

聊天的时候被问到,“单设备/多设备/单点登录的架构如何设计?”

这里是对方案二的改进,我们将username作为Key,但是不是只有一个username,那样的话是能对应一个Token了,就是单设备登录了

那我就设计成三个username作为Key,pc_username、mobile_username、ipad_username

每个username分别对应不同端的设备,目前就是电脑、手机和Ipad了。

那我们如何得知用户到底是哪种设备呢?

我们可以基于HTTP请求头部中的User-Agent字段,该字段包含了浏览器或客户端发送的关于自身信息的数据,包括设备类型等...信息

  1. 后端解析User-Agent:

    当用户发起登录请求时,服务器读取请求头中的User-Agent字符串

  2. 识别设备类型:

    通过验证User-Agent的内容来识别设备类型,如"Mobile"、"iPhone"、"iPad"、"Android"、"Windows NT"等

  3. 对不同设备进行分类:

    根据解析结果将设备大致分为手机、平板和电脑,如果User-Agent中包含“iPhone”、“Android”或其他智能手机标识,则认为是手机;如果包含“iPad”或者特定的平板标识符,则认为是平板;若包含“Windows NT”、“Macintosh”或常见桌面浏览器标识,则可能判断为电脑。

  4. 进行登录控制策略

public void getRequestHeader(HttpServletRequest request){
    // 从浏览器获取请求头信息
    String info= request.getHeader("user-agent");
    if(info.contains("Windows")){
        System.out.println("Windows pc端登陆");
        return;
    }
 
    if(info.contains("Macintosh")){
        System.out.println("Mac pc端登陆");
        return;
    }
 
    if(info.contains("Android")) {
        System.out.println("Android移动客户端");
        return;
    }
 
    if(info.contains("iPhone")) {
        System.out.println("iPhone移动客户端");
        return;
    }
 
    if(info.contains("iPad")) {
        System.out.println("iPad客户端");
        return;
    } 
    System.out.println("其他客户端");
}

4.单点登录

这里拓展一下单点登录的架构设计

在单体架构的服务中,以Java举例,单个SpringBoot服务中,是不需要考虑单点登录的问题的,反正就一个整体服务对外提供服务

根本不会存在单点登录的问题,那么微服务的单点登录真的是你想的那样吗?

  • 每个应用单独对token进行去验证

聊天的时候被问到,“单设备/多设备/单点登录的架构如何设计?”

这么一看这样好像没什么问题,挺好的,但是不觉得功能有点耦合了吗,每个应用都需要单独的去验证token是否有效,用户是否登录

我们能不能把登录认证、权限认证单独抽出来进行统一鉴权

  • 网关统一鉴权

聊天的时候被问到,“单设备/多设备/单点登录的架构如何设计?”

auth服务:这个服务承载了我们所有的基础数据源。他不管鉴权,只管数据相关的持久化操作以及业务操作,提供出各种各样的权限相关的接口。

gateway网关层:对所有请求进行鉴权,避免每个服务对鉴权进行耦合