V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
DimitriYoon
V2EX  ›  Java

公司内部系统单点登录求求大佬给个方案

  •  
  •   DimitriYoon · 2022-02-23 11:02:47 +08:00 · 5535 次点击
    这是一个创建于 997 天前的主题,其中的信息可能已经有所发展或是发生改变。

    公司想把以前的项目集中起来 我用 SpringCloud alibaba 搭了一个架子,用 gateway 做的网关,Spring Security Oauth2 做一个认证模块。 现在想要在后续的开发中把其他系统也集成到这个微服务中,然后统一从认证模块登录,登录完成之后其他模块不再需要登录。

    但是目前是前后端分离的模式,前端是用 nginx 跑的,如何实现我现在毫无头绪,球球大佬们解答惹!

    37 条回复    2022-09-02 15:32:06 +08:00
    THESDZ
        1
    THESDZ  
       2022-02-23 11:34:00 +08:00
    说个我认为最简单的

    认证单独部署一个服务,账号 /用户单独一个服务。

    认证服务提供 token

    网关拦截和解析 token ( jwt 或者对接认证服务)获取用户唯一标识,把用户唯一标识塞在请求头里面,传给后续请求

    各个应用直接写个注解 aop ,有需要就 @注解后,把用户信息塞到某个参数的对象实例里面
    DimitriYoon
        2
    DimitriYoon  
    OP
       2022-02-23 11:44:05 +08:00
    @THESDZ 不打算用 JWT ,我用的 redis 管理令牌,这样方便注销令牌,但是目前我不知道前端该如何校验用户是否登录过...而且后端和前端端口不一致
    gadfly3173
        3
    gadfly3173  
       2022-02-23 11:47:00 +08:00   ❤️ 1
    大厂比如阿里云之类的,都是直接用 cookie-session 解决的,把 session 存 redis 就行。再搞自己的 token 之类的也只是重新实现一遍 cookie-session 干的事

    gadfly3173
        4
    gadfly3173  
       2022-02-23 11:50:00 +08:00   ❤️ 1
    @DimitriYoon #2 你完全不需要考虑前端,最多只需要考虑个 cookie 的 domain 的设置。后端每个接口都会经过认证服务,没通过的就返回个 401 ,前端只要检测到 401 就弹到登录页就好了
    brader
        5
    brader  
       2022-02-23 11:54:51 +08:00   ❤️ 1
    你原有的认证方式无非就是 token 模式,或者 session 模式,你把 token 或 sessionid 搬到 redis 上去,这样就是分布式的。
    然后每个项目都去 redis 拿这个 token 共用,这样就全部都能认证登录了。

    登录认证检查你也可以统一写在用户中心,然后有用户中心统一提供接口。

    喜欢哪种模式就看你了。
    DimitriYoon
        6
    DimitriYoon  
    OP
       2022-02-23 11:58:13 +08:00
    @gadfly3173 您的意思是不需要用 token ?直接用 session ?
    DimitriYoon
        7
    DimitriYoon  
    OP
       2022-02-23 12:02:50 +08:00
    @brader 前端的话是 nginx 部署的多个站点,比如 a 模块前端的地址是 xxx.xxx.xxx.xxx:10000 ,然后 b 模块前端地址是 xxx.xxx.xxx.xxx:10001 ,那么如果我通过登录的前端地址 xxx.xxx.xxx.xxx:9999 登录了之后,10000 如何得知 9999 给的 token
    gadfly3173
        8
    gadfly3173  
       2022-02-23 12:12:01 +08:00
    @DimitriYoon #7 cookie 不区分端口,也可以一定程度上的跨域(通过设置 domain ),所以我才推荐用 cookie 解决单点登录。如果你的 token 是前端存在 localstorage 里的话就做不到跨域单点登录了
    Herry001
        9
    Herry001  
       2022-02-23 12:13:18 +08:00
    参考下 Oauth2.0?
    gadfly3173
        10
    gadfly3173  
       2022-02-23 12:15:31 +08:00
    @Herry001 #9 Oauth2 的话还能算单点么。。?每个域名都得点一次授权登录
    DimitriYoon
        11
    DimitriYoon  
    OP
       2022-02-23 12:16:55 +08:00
    @gadfly3173 如果使用 cookie 的话,是否可以抛弃 oauth2 ,单纯用 security 做?
    aofall
        12
    aofall  
       2022-02-23 12:28:01 +08:00   ❤️ 1
    Jwt 只是令牌签发验证的一种方式而已,如果签发时不指定过期时间,签发出来的令牌存在 Redis 用于管理过期时间,和 Cookie-Session 的作用就一样了。

    区别就是 Redis 管理令牌,在没有限制、数据库分区一致的情况下多个系统都是可以从 Redis 中读到这个登录令牌的,只要保证密钥一致就相当于变相的实现一个简单的单点登录(当然这样可能会有令牌管理混乱的问题,可以根据系统规模考虑一下是否要这么做)
    DimitriYoon
        13
    DimitriYoon  
    OP
       2022-02-23 12:45:36 +08:00
    @aofall 多个前端站点如何获取认证模块下发令牌呢...?
    frank1256
        14
    frank1256  
       2022-02-23 13:20:46 +08:00   ❤️ 1
    基于 SpringSecurity 的 Oauth2.0 ,使用授权码模式。
    有几个角色,如下
    1 、授权中心,用于发放 token ,对应的注解是 @EnableAuthorizationServer
    2 、用户微服务,提供用户信息和权限的 crud ,是一个资源服务器,对应 @EnableResourceServer

    授权流程:
    前端以 vue 为例,在登陆之前检查本地是否有 token ,没有的话使用授权码模式,跳转到授权中心的统一登录界面,授权码模式回返回到前端并且带上授权码,前端拿到授权码调用授权中心获取 token 的接口。拿到 token ,之后调用用户微服务获取用户信息和权限,渲染前端。

    无需重复登录:
    多个前端,跳转的都是授权中心的同一个登录界面,也就是同一个 session ,在浏览器不关闭的情况下,一个前端跳转后完成登录,第二个前端再次跳转到这里,不需要再登录。会根据后端配置,是否需要授权。如果需要授权,需要点击一次,可以配置不需要授权配置 autoapprove 字段。那么第二个前端在用户体验上,只是单纯的跳转两次后,一样会带着授权码回到第二个前端,和第一个前端一样,调用 api 获取 token 。达到不需要重复登录的目的。在 oauth_client_details 的表设计里有 autoapprove 字段,就是用于自动授权。

    oauth2.0 是分应用的,不同应用的 token 是不一样的
    DimitriYoon
        15
    DimitriYoon  
    OP
       2022-02-23 13:41:34 +08:00
    @frank1256 内部系统不需要用到授权码模式呢,我只用了 password 和 refresh_token
    frank1256
        16
    frank1256  
       2022-02-23 13:45:03 +08:00
    @DimitriYoon 为什么不用授权码模式呢,用 password 的,还需要有自己的登录界面,每个系统难道都要自己做一套登录界面吗,授权码模式就是为了统一登录的。password 没有什么好的方法,只能自己造轮子。refresh_token 是过期去替换的。
    Casbin
        17
    Casbin  
       2022-02-23 13:47:21 +08:00
    @DimitriYoon 可以看下开源单点登录系统 Casdoor ,作为统一的认证+用户中心: https://v2ex.com/t/803669
    9c04C5dO01Sw5DNL
        18
    9c04C5dO01Sw5DNL  
       2022-02-23 13:49:58 +08:00
    oauth2 不是给三方授权的吗?一方系统用不着啊
    DimitriYoon
        19
    DimitriYoon  
    OP
       2022-02-23 13:50:33 +08:00
    @frank1256 我考虑了一下,可能还是用 redis 共享 session 的方法靠谱一点,毕竟这套系统不需要对接外部,而且用 oauth2 的话,各个系统还得额外点一下授权
    9c04C5dO01Sw5DNL
        20
    9c04C5dO01Sw5DNL  
       2022-02-23 13:53:35 +08:00   ❤️ 1
    另外 redis+token 就是 session 方案,不管你的 token 是 jwt 还是其他 token 。

    jwt 所谓的无状态,是指自包含状态,每次请求时携带状态。

    如果状态下沉到持久 /缓存层,jwt 所谓的无状态并没什么太大的优势。


    强烈建议各位看下 redis 官方博客这篇文章: https://redis.com/blog/json-web-tokens-jwt-are-dangerous-for-user-sessions/
    yogogo
        21
    yogogo  
       2022-02-23 13:53:58 +08:00   ❤️ 1
    看你描述,你对前后端分离不是很了解啊,这就开始搭架子这不是在给自己找坑吗
    DimitriYoon
        22
    DimitriYoon  
    OP
       2022-02-23 14:01:29 +08:00
    @yogogo 嗯哼?能说说您的概念吗?
    DimitriYoon
        23
    DimitriYoon  
    OP
       2022-02-23 14:02:32 +08:00
    @giiiiiithub 所以我感觉没有必要再用 token 的方式了,直接 session 梭哈
    MYlyc
        24
    MYlyc  
       2022-02-23 14:05:58 +08:00   ❤️ 2
    建议用 sa-token ,看看文档里对于单点登录的方案
    SjwNo1
        25
    SjwNo1  
       2022-02-23 14:08:44 +08:00
    虽然但是,cookie-session 吧
    DimitriYoon
        26
    DimitriYoon  
    OP
       2022-02-23 14:09:28 +08:00
    @MYlyc 十分感谢,我看了一下文档确实非常不错!
    JKeita
        27
    JKeita  
       2022-02-23 14:20:19 +08:00
    统一服务登录,登录会话保存在服务端,之后其他前端项目通过接口请求自己项目服务端获取登录信息,没有获取到则让前端跳转到统一登陆服务界面并且带上回调的项目接口地址,统一登录服务验证已经通过重定向到项目回调地址并带上一个 token ,然后前端将该 token 保存本地,并通过该 token 去取用户登录数据。
    yogogo
        28
    yogogo  
       2022-02-23 14:26:06 +08:00   ❤️ 1
    @DimitriYoon
    #22 前后端分离,后端只要关心请求是否认证过就行了,至于前端如何校验认证就不用管了;如果所有请求都是走 gateway ,那只要 gateway 做一个认证登陆的入口,认证后返回 token ,请求的时候带上认证的 token ,交给 gateway 统一认证就行了;
    jwt 跟 session 只是存放认证位置不同而已,本质是一样的;
    DimitriYoon
        29
    DimitriYoon  
    OP
       2022-02-23 14:31:28 +08:00
    @yogogo 其实我的问题还是如果采用 token 的情况,前端不同域无法传递 token ,比如我认证服务器下发,用户从前端拿到了 token ,不同域的其他站点如何拿到呢。我的问题其实是后端如何写才能配合前端多站点的部署方式
    JKeita
        30
    JKeita  
       2022-02-23 14:45:42 +08:00
    @DimitriYoon 你在统一登录界面登录之后,只要通过页面跳转,就能把 token 传给不同域名的前端。
    0312birdzhang
        31
    0312birdzhang  
       2022-02-23 14:46:22 +08:00
    9136347
        32
    9136347  
       2022-02-23 14:46:47 +08:00
    ldap
    GayGayUp
        33
    GayGayUp  
       2022-02-23 15:28:56 +08:00
    Spring Security Oauth2 太复杂,sa-token 了解一下,比较简单。
    zzl22100048
        34
    zzl22100048  
       2022-02-23 17:25:03 +08:00
    @GayGayUp @frank1256
    Oauth2 是授权协议,OIDC 才是认证协议
    rootit
        35
    rootit  
       2022-02-23 18:02:21 +08:00
    1 用户输入账号密码
    2 经过统一认证服务的登录接口校验,成功多加一个 header Auth:base64 值 ,这个值可以是 uuid 反正就是跟 redis 里 set 的用户登录信息能关联就行
    3 其他系统不就有这个 header 了 注销就把 redis 里的用户登录信息清理了
    4 其他系统通统一认证服务的 /auth 或者 /getOwn 接口校验是否登录,如果带着合法的 header 返回正常,不合法返回未登录。
    Cookieeeeee
        36
    Cookieeeeee  
       2022-02-23 18:13:54 +08:00
    目前的这个 体验不错 https://authing.co/
    sanyuedev
        37
    sanyuedev  
       2022-09-02 15:32:06 +08:00
    @gadfly3173 这个不错,但是要怎么去控制,用户只能访问特定的系统呢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2844 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 08:30 · PVG 16:30 · LAX 00:30 · JFK 03:30
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.