从我刚开始学习互联网方面的编程开始,无论是写什么项目(除了微信公众号的消息收发),用户都是一个耗时间、耗精力而又无法保证开发最终稳定、无法复用的功能。对于每个业务需求,有一半的时间都是去做用户系统。从最开始的原生 PHP 手写笨拙的注册流程和表单,到 ThinkPHP(呕),再到后来的 Laravel 开箱即用的认证模块——虽然说是开箱即用,但国外的邮箱策略和国内的手机号、微信授权功能对比,开发成本还是很大的。并且,对于多产品来说,用户信息的集中也是个必要的功能。所以,相对于开发 N 多个用户系统,不如使用单一的用户系统,然后从其他的系统中通过 token、cookie 等方式进行同步维护状态。这也是我们常说的单点登录(Single Sign-On,SSO)。
无论是作为一个企业,还是一个有小项目的开发者(Both of me),都需要有一个合适的用户系统做支撑。写项目至今,接触过的认证方式和认证系统,综合对比一下。
协议
用户中心系统作为服务端,肯定是要跟客户端进行对接来授权&获取用户信息的。目前大致流行的有 LDAP、CAS、OIDC(基于 Oauth2.0)、SAML 等,此外还有 Kerberos 等不太常见的协议。其宗旨基本一致:浏览器向客户端发起请求,客户端访问用户系统获取 Cookie 或其他认证条件,由用户系统负责登录并将认证后的条件返回给客户端。
LDAP
Lightweight Directory Access Protocol,轻型目录访问协议。这个协议稍微有接触过企业服务的同学可能都不陌生,这是比较古老的认证协议,但至今仍在企业内部和大部分的用户系统中提供支持。LDAP 是文件型存储的,通过 IP 协议进行用户认证授权,层级结构分明,特别适用于公司内部的用户系统。新员工入职时,只需要添加一个 LDAP 成员,就可以访问 wiki、gitlab、oa 等所有系统了。百度、阿里、饿了么等大部分互联网公司内部均采用此协议进行员工管理。具体参考: [https://ldap.com/](https://ldap.com/)
CAS
CAS 是由耶鲁大学实验室 2002 年出的一个开源的统一认证服务中的标准协议,也是很多企业内部系统登录所使用的标准协议,如阿里巴巴等。作为 C 端登录协议如支付宝、淘宝等。详细协议标准可以参考
[https://apereo.github.io/cas/6.4.x/protocol/CAS-Protocol-Specification.html](https://apereo.github.io/cas/6.4.x/protocol/CAS-Protocol-Specification.html)
。其核心是服务端返回 ticket 作为认证条件,由客户端判断条件是否存在,存在则通过验证接口验证用户登录状态,同时返回用户信息,否则进行登录。同时客户端可以自定义登录流程,通过服务端提供的接口进行认证。总体流程如图[^1]:
使用方也就是 Apereo CAS,此外有少数的语言也按此协议开发了不同的服务端,不过应用甚少。
OIDC(Oauth 2.0 实现)
Open ID Connect 是基于 Oauth 2.0 的开放身份认证协议。Oauth2 本身是一个认证协议,它提供了一个授权流和标准通用协议,其中并没有有关用户身份认证相关的内容。OIDC 在此基础上实现了用户相关的认证,完全兼容 Oauth2.0。所以我们常见的微博、QQ、微信等开放平台,文档概述是 Oauth2.0 协议,其实采用的也是非标准结构的 OIDC,因此大家基本谈到的 Oauth2.0==OIDC。
OIDC 是目前应用比较广泛的用户认证协议,官网: [https://openid.net/connect/](https://openid.net/connect/) 。最基本的是授权码模式,然后支持直接授权流、隐式授权流、密码授权等客户端对等认证、一次性认证等方式进行授权流程。
授权码模式基本流程就是客户端向服务端发起请求,带着 state、client_id、client_secret、redirect_uri、scope 参数请求服务端的授权接口,服务端打开自己的授权页进行授权后,会回调给 redirect_uri 地址,带有 code 参数,客户端通过 code 向服务端换取 access_token,然后就可以拿 token 去做任何事情了。(懒得画图。。)
OIDC 在所有(没有几乎)语言、框架中均有提供,所有的用户系统也都支持,因此这是一个非常广泛使用的协议。我们平时常见的微信授权登录、QQ 授权登录、Github 登录无一不采用此认证方式。
SAML
Security Assertion Markup Language,安全断言标记语言。一个基于 xml 的在不同安全域间进行交换认证和授权数据的协议,是很经典的一个授权协议。因此在大部分的用户系统中,都会有 SAML 协议的支持。不过国内使用的还是偏少,OIDC 的出现抢了它的风头。简介可以参考维基百科: [安全断言标记语言](https://zh.wikipedia.org/wiki/%E5%AE%89%E5%85%A8%E6%96%AD%E8%A8%80%E6%A0%87%E8%AE%B0%E8%AF%AD%E8%A8%80) ,其官网(没有找到官网)。
其他
此外,还有很多用户认证的协议如 Active Directory、Kerberos 等大大小小的协议,在此不一一列举。
框架 & 平台
很多框架或语言本身提供了搭建 SSO 的工具、脚手架,如 [Laravel Passport](https://laravel.com/docs/8.x/passport)、[Go Auth Server](https://pkg.go.dev/gopkg.in/oauth2.v3) 等,在此不一一列举,基本都是基于 OIDC 协议进行开发的。而支持单点登录的客户端如 Confluence(私有部署版)、Gitlab(私有部署版)、Laravel、WordPress(有个收钱很贵的插件)等,也都是支持 OIDC 的,其中前两者也支持 LDAP,Gitlab 也支持 SAML 协议。讲道理,自己开发最快的方式可能还是基于 OIDC 协议进行认证授权吧。
在这里整理一下自己尝试过的 SSO 平台,其中包括开源、收费和云原生的,不争高低,合适就好。
Apereo CAS
官网:[https://apereo.github.io/cas/6.4.x/index.html](https://apereo.github.io/cas/6.4.x/index.html)
这是老牌的 SSO 系统,Java 语言开发,至今仍在积极维护,有完整的发布时间表和维护周期。以下是官网介绍的特性:
Spring Webflow/Spring Boot Java server component.
其可插拔认证支持、多协议支持、OTP 支持等等非常多的功能均是亮点。还是刚才说的,内部系统很多都在使用其二次开发或扩展的 CAS,如阿里巴巴。
部署支持 Docker、原生 war。
开发采用 `CAS Overlay` 的方式,就是说在第一次部署后,将某个资源文件或 class 文件复制到你的`src/main`目录下进行二次开发,在 package 的时候会自动将你的文件替换到原有项目中去,实现功能自定义的目的。
最新版的(6.4)CAS 默认的登录界面如下:
是使用 Docker 启动的。登录后界面也十分简单,在左侧有相关文档链接的侧边栏。基础启动方法可以参考其他人的文章:[https://www.cnblogs.com/zhzhlong/p/11551361.html](https://www.cnblogs.com/zhzhlong/p/11551361.html)
CAS 是一个专注于认证的系统,因此——没有注册功能,默认是内存存储用户信息,一切配置均采用 Java 的 yaml 格式文件。因此,如果你想用 MySQL 作为存储引擎,那么你需要引入`mysql-connector`然后再在 yaml 中配置好数据库连接、表结构等信息。而注册等功能需要通过 overlay 的方式进行扩展。而 overlay 我是尝试过的,用起来可以说是相当复杂。其自定义后的 Docker 镜像也是要重新编译的。
总而言之,CAS 本身是一个十分强大的用户认证系统,相关开源的插件也很多。但其因为过于强大而专一,导致我们平时很需要的额外功能反倒不支持,想把 CAS 作为生产环境使用将会有很大的工作量。而且文档也并不是很详细。接入 CAS 需要其支持客户端语言,如 PHP-CAS 等。
Keycloak
官网:[https://keycloak.org](https://keycloak.org/)
Keycloak 于 2013 年末发布 1.0-alpha 版,到现在最新版已经是 15.0.2 了,16.0.0 在紧锣密鼓地开发中。这是一个支持比较完整的用户认证系统,由 Java 开发,基于 jboss。
就在写这段的时候,Keycloak 官网发布了一条消息,迎来的新的 maintainer: Tomas Darimont,主要负责 keycloak.X 的开发。
相对于 CAS,Keycloak 没有那么多的协议的支持,认证协议支持 OIDC 和 SAML,将 LDAP 和 Kerberos 作为用户存储协议集成。使用 Freemarker 作为 HTML 模板。内置第三方授权登录。通过 jboss 提供的热加载服务可实现扩展。内置的所有功能都可以扩展。支持注册!原生支持 Postgres、MySQL、SQLite 等数据库引擎。
而且,其默认的登录界面基本没有侵略性。如图:
部署支持 Docker、原生部署等。内置管理控制台,支持多 realm。默认提供一个 Master 的 realm 供整体管理使用,一般我们都会建立自己的 realm。
扩展方式是基于[https://www.keycloak.org/docs/latest/server_development/index.html](https://www.keycloak.org/docs/latest/server_development/index.html),将要自定义的功能定义为一个 SPI,部署到 deployments 目录里即可。主题也可以自定义,方式是通过编写 base 模板的 css 来实现。上图的主题是内置的`keycloak`主题。
当然,缺点也是有的,比如支持的协议不够多,用户的存储无法自定义,文档也不够详细~~(到底要多详细的模板才满意)比较重要的是,其用户属性是可以扩展的,但是默认的必填项是无法删除的,比如国外常用的`First Name`、`Last Name`,而我们可能只需要一个昵称,取消前两者的必填属性就需要一定的开发了。
这里是我同事写的 Keycloak 的基础搭建过程:[https://zhuanlan.zhihu.com/p/411062890](https://zhuanlan.zhihu.com/p/411062890)
目前 keycloak 的扩展基本跟不上其更新速度,基本都停留在 12.0.1 的版本。我用了到目前三个星期的时间来适配不同的插件,包括 oauth、短信验证等。这里可以放出来一个看看:[https://github.com/rxrw/keycloak-justauth](https://github.com/rxrw/keycloak-justauth)是基于 justauth 让 Keycloak 支持国内数十种平台的第三方授权登录。
Demo: [https://auth.iuv520.com/auth/realms/test/account/#/](https://auth.iuv520.com/auth/realms/test/account/#/),我内置了一个通用的 key & secret,感兴趣的同学可以自己搞个客户端来体验一下。
client_id: test
client_secret: eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJmZGYxNmJjOS04M2U0LTRjZmEtOWRiZC0yNTE1OWQyMWE3YWEifQ.eyJleHAiOjE3MTgyNjYxMDcsImlhdCI6MTYzMTg2NjEwNywianRpIjoiMmQxOTBjODgtZWQ5NC00ZDEwLWIwMGUtZDcwZjY2MWQwOTZlIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLml1djUyMC5jb20vYXV0aC9yZWFsbXMvdGVzdCIsImF1ZCI6Imh0dHBzOi8vYXV0aC5pdXY1MjAuY29tL2F1dGgvcmVhbG1zL3Rlc3QiLCJ0eXAiOiJJbml0aWFsQWNjZXNzVG9rZW4ifQ.CNgndfSSJo-ahVFVFSlRehayPSCRr9I6tiuc5hXulrU
redirect_uri: *
授权地址: https://auth.iuv520.com/auth/realms/test/protocol/openid-connect/auth
token地址: https://auth.iuv520.com/auth/realms/test/protocol/openid-connect/token
用户信息: https://auth.iuv520.com/auth/realms/test/protocol/openid-connect/userinfo
auth0
官网:[https://auth0.com](https://auth0.com/)
与前两个不同,auth0 是国外一个云原生(Cloud Native)用户认证系统,要 💰 的商业化平台。免费版可以支持 7000 用户。作为一个云原生项目,特点就是不需要存储、不需要很多开发就可以使用(登录 UI 可以自定义)。但是对于用户系统,把自己公司的用户数据放到别的平台,可能是需要思考一下。登录流程会走 auth0 自己的服务器,虽然可以自定义域名,但本质没有改变,对于国内用户来说速度无法接受。因此自己玩耍一下还可以。
不是要搭建自己的用户平台么,怎么用上人家的了..
authing
官网:[https://www.authing.co/](https://www.authing.co/)
这是国内少有的还比较成型的身份认证系统,开发语言 NodeJS。与 auth0 类似,其也是一个云原生平台。虽说不用服务器,每月的价格也够一台不错的阿里云服务器了。
整体的架构和 Auth0 差不多,第三方授权登录都是微信等国内常用的授权方式。
也是各种用户数据存储在第三方,难道真的有企业会愿意把自己的用户信息放在别人那里管么。因此支持私有部署,不过就之前与其进行对接的经历,感觉系统内部的代码其实很乱,基本私有部署也没什么定制化的空间。
总结
其实真正开源的用户系统也就 CAS 和 Keycloak 两家比较完善且流行的。如果有特别严重的定制化需求,建议还是采用自己开发的方式吧。毕竟国外的用户系统不一定合我们的胃口,而国内的某些平台吃相也是真的难看。如果定制化需求没那么严重,可以在现有开源项目的基础上扩展,那是最好的了。我现在就是在 Keycloak 的基础上进行的扩展,感觉经过一定修改和兼容后,产品可用性还是很强的。