ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

认证与鉴权选择指南:JWT、OAuth 2.0、RBAC、ABAC、Keycloak

认证与鉴权选择指南:JWT、OAuth 2.0、RBAC、ABAC、Keycloak 一个服务刚上线没用户没登录。调用方都是内部系统相互信任——IP 白名单就够了。后来用户来了。要区分谁是谁。再后来有管理员、有普通用户、有只读用户。角色一多权限判断就散在代码里——if user.role admin写了二十遍改一次要改二十个文件。这时候你才开始看认证鉴权方案。不是看谁文档最全是看你的场景卡在哪一层。认证和鉴权先分清认证Authentication回答「你是谁」——登录、验证身份、确认对面是本人。鉴权Authorization回答「你能做什么」——查权限、判角色、决定这个请求能不能过。先认证身份再查权限。认证在前鉴权在后。两件事混在一起改一个影响另一个——分开就各管各的。认证Session vs JWT传统 Session最直觉的做法用户登录成功后服务端生成一个 session 存 Redis 里返回一个 cookie。下次请求带 cookie服务端查 Redis 找对应的 session找到就知道是谁。客户端 → 登录 → 服务端生成 session → 存 Redis → 返回 cookie 下次请求 → 带 cookie → 服务端查 Redis → 找到 session → 通过够简单。服务端控制一切——session 丢了立马清权限改了立马生效。但代价在状态。每个请求都要查一次 RedisRedis 挂了所有用户掉线。扩到多实例每个实例都要访问同一个 Redis延迟加一跳。防 CSRF 要自己加 token防 session 劫持要设 HttpOnly、Secure。JWTJWT 换了个思路不存状态把用户信息直接编码进一个 token 里。服务端签发——签了名改不了。客户端带着 token 来服务端验签名验完直接用里面的信息不用查任何中央存储。JWT 分三段Header用什么算法、Payload用户 ID、过期时间、角色、Signature前两段用密钥签名。三段用.连起来对机器是个字符串对人是个长串。Header.Payload.SignatureJWT 的好处是无状态。任何实例都能验——不用查 Redis不用查数据库。扩缩容跟它无关。微服务之间传身份一个 JWT 就够了——A 服务调 B 服务把 JWT 带上B 自己验不用问 A「这人是谁」。JWT 的代价是没法主动失效。签出去了在过期时间之前服务端想让它失效——做不到。token 在客户端手里服务器没任何办法让它提前作废。要失效只能靠黑名单——每次请求查一遍黑名单——等于又回到中心存储。JWT 把「无状态」换成了「没法主动控制」。JWT 最典型的踩坑把权限放 payload 里。Payload 是 Base64 编码不是加密——任何人拿到 token 都能解码看到里面内容。把roleadmin放 payload安全。把permissionread_all_financial_data放 payloadtoken 一泄露权限全暴露。JWT 里的信息是公开的——不是加密是签名。签名的意义是「没人能改」不是「没人能看」。怎么选单服务、在乎实时控制、不介意查 Redis——Session。简单可控要失效随时失效。单体应用天然选它。微服务、多实例、不想每次都查中心存储——JWT。无状态服务间传身份方便。但要接受 token 没法主动失效。既要无状态、又要能失效——JWT 短过期 Refresh Token。JWT 设 15 分钟过期过期了用 Refresh Token 换新的。Refresh Token 存在服务端能随时吊销——长期状态的主动权还在服务端手里。鉴权从代码到模型身份确认了接下来是权限。权限有四种模型不是谁比谁好是看你的关系复杂到什么程度。RBAC最直接的RBAC 是 Role-Based Access Control——角色 权限。用户有角色角色有权限权限控制操作。中间加了一层角色用户和权限就不直接耦合了。用户 → 角色 → 权限 → 资源三个角色管理员、编辑、只读管几百个用户——改权限只改角色不用一个个用户改。大部分系统用 RBAC 就够了。但 RBAC 的问题是到不了资源级。「编辑能改文章」——改哪篇所有篇。「管理员能看数据」——看哪个表的所有表。RBAC 是资源类型级的——能改文章不能改某篇特定的文章。一旦需要「这个用户只能看他所在部门的订单」RBAC 就装不下——要加属性。ABAC把属性加进去ABAC 是 Attribute-Based Access Control——不只看角色还看属性。用户部门销售 资源订单 操作读 环境内网→ 允许不是「销售能看订单」是「销售能看他自己部门的订单」。属性把权限从类型级缩小到实例级。但 ABAC 的代价是复杂度。属性多了规则就多——用户的部门、资源的所有者、操作的时间、环境的 IP、当前的时间段。五六个维度交叉一条规则写错要么拦不住要么全拦住。而且规则多了排查困难——一个用户被拒了不知道是哪条规则拒绝的。RBAC 的审计是「这个用户是什么角色」ABAC 的审计是「这二十条规则哪条生效了为什么」。ACL最细但最重ACL 是 Access Control List——每条资源直接挂权限列表。文件 A用户 1 可读用户 2 可写用户 3 不可见 文件 B用户 1 可写用户 2 不可见ACL 的粒度是资源级的但管理成本是用户级。一百万个文件每个文件都要挂权限——改一个人要翻遍所有文件。RBAC 的用户变了角色角色自动生效ACL 的用户变了权限要一个个资源改。ACL 适合资源少、用户少、但粒度要精确的场景——文件系统、云存储桶策略。不适合用户多、资源多的场景——管理成本随资源数线性增长。怎么选角色多、但权限不精细到具体资源——RBAC。简单够用大部分系统的答案。权限要精细到具体资源、具体场景——ABAC。但要接受规则复杂度——规则多了排查和审计都难。上 ABAC 之前先问你真的需要这么细吗还是 RBAC 加几个if就能解决资源少、用户少、但每个资源的权限都不同——ACL。云存储、文件系统、K8s RBAC 背后实际是 ACL。刚开始、不知道以后会不会复杂——先 RBAC。复杂了再往上加属性。不要一上来就 ABAC。OAuth 2.0不是认证是授权一个常见误解OAuth 2.0 是登录。其实不是。OAuth 2.0 是委托授权——允许第三方应用代表你去访问你的资源但资源在你手里不在第三方手里。「用 Google 登录」Google 告诉这个网站我是谁 → 这是 OIDC 「允许这个 App 读我的邮件」我授权这个 App 去 Google 拿我的数据 → 这是 OAuth 2.0OIDCOpenID Connect才是身份认证——建在 OAuth 2.0 上面的一个薄层。OAuth 2.0 负责授权OIDC 负责认证——OIDC 在 OAuth 返回的 token 里多加了一个 ID Token告诉调用方「这个人是谁」。OAuth 2.0 的四种模式OAuth 2.0 别当「一种协议」记当「四种模式」——每种对应不同场景。Authorization Code授权码模式用户→浏览器→授权服务器→返回授权码→后端拿授权码换 token。服务器对服务器你的后端和 Google 的后端在通信。最安全因为 token 不经过浏览器。Client Credentials客户端凭证模式服务对服务没有用户——后端直接拿 client_id client_secret 换 token。微服务之间的认证。不是登录是「这个服务确认自己是自己」。Implicit隐式模式已废弃。token 直接返回给浏览器——太暴露了URL 和 referrer 都可能泄露。Password密码模式也被废弃。用户名密码直接交给第三方——第三方完全可以记录你的密码。选 OAuth 模式不是选哪个好——是选「用户在场还是不在场」「浏览器参与还是不参与」。有用户、有浏览器——Authorization Code。没用户、只有服务间——Client Credentials。都不要用密码模式——那是把自己密码交给别人信任太强了。怎么选整体看回过头看不是比谁的协议更完善是搞清楚你现在的需求卡在哪一层。先分清你在选认证还是鉴权。认证是「谁在敲门」鉴权是「门开了之后你能去哪」。两个问题两套方案。单体应用、用户不多、内部系统——Session RBAC。简单好排查改权限立马生效。微服务、跨服务调用、不想每个请求都查中心——JWT OAuth 2.0 Client Credentials。服务间传 JWT服务自己验。对外开放、让第三方访问用户数据——OAuth 2.0 Authorization Code。不要自己造轮子用 Keycloak、Casdoor、Authentik。OAuth 是趟过的路坑都在协议里修过了。权限精细到具体资源、具体场景——ABAC。但要接受规则复杂度的代价——规则多了排查难。大部分场景 RBAC 加几个if就够。已经在云上、不想自己搭认证服务器——云厂商的 IAMAWS IAM、阿里云 RAM。云厂商替你管用户、管权限你自己只管策略。开源、自建、想控制一切——Keycloak。OIDC OAuth 2.0 SAML 全支持自带 UI用户管理不用自己写。缺点是要自己运维——多部署一个服务就多一个要监控、备份、升级的东西。最后一条不要在代码里散落权限判断。if user.role admin写一次没事写二十次就是安全漏洞——漏改一个要么权限不够要么权限太宽。权限判断收敛到一处中间件、网关、或策略引擎改了全部生效。代码里散着的权限判断不是逻辑是负债。
返回列表