在当今的互联网生态中,第三方应用授权登录已成为常态——我们登录某款APP时,常常会选择“使用微信登录”“使用QQ登录”或“使用GitHub登录”,无需单独注册账号即可快速完成认证。这一便捷体验的背后,核心支撑技术便是OAuth 2.0。OAuth 2.0是一个开放的授权协议,其核心目标是在不泄露用户账号密码的前提下,让第三方应用安全地获取用户在特定服务提供商处的资源访问权限。本文将从OAuth 2.0的核心角色、核心授权模式入手,结合时序图详细拆解各模式的执行流程,帮助读者彻底理解其工作原理。
一、OAuth 2.0的核心角色
OAuth 2.0协议定义了4个核心角色,各角色分工明确,共同完成授权流程。理解这4个角色是掌握OAuth 2.0的基础:
- 资源所有者(Resource Owner):通常是终端用户,即拥有待访问资源的主体。例如,使用“微信登录”某游戏时,你就是资源所有者,微信账号下的个人信息(昵称、头像等)就是待访问的资源。
- 客户端(Client):需要获取用户资源的第三方应用。例如,上述场景中的游戏APP就是客户端,它需要获取你的微信个人信息来完成账号注册与登录。客户端在使用OAuth 2.0授权前,需先在授权服务器完成注册,获得唯一的“客户端ID”和“客户端密钥”(用于身份验证)。
- 授权服务器(Authorization Server):由资源服务提供商(如微信、QQ)部署的服务器,负责验证资源所有者的身份、接收并处理授权请求,最终向客户端发放“访问令牌”(Access Token)。例如,微信的授权服务器就是负责验证你的微信账号密码、确认你是否同意游戏APP获取个人信息的核心组件。
- 资源服务器(Resource Server):同样由资源服务提供商部署,存储并对外提供用户的受保护资源。客户端获取访问令牌后,需携带令牌向资源服务器请求资源,资源服务器会验证令牌的有效性,通过后才会返回对应的资源。例如,微信的资源服务器存储着你的昵称、头像等信息,游戏APP携带访问令牌向其请求时,资源服务器验证令牌有效后,会将你的个人信息返回给游戏APP。
补充说明:在很多实际场景中,授权服务器和资源服务器可能会合并部署(例如微信的授权服务器和资源服务器属于同一套系统),但从协议设计上,两者是独立的角色。
二、OAuth 2.0的核心授权模式
OAuth 2.0定义了5种授权模式,分别适用于不同的场景(如客户端是否有服务器、是否能安全存储密钥等)。其中,授权码模式是最常用、最安全的模式,其余模式则适用于特定的简化场景。下面将逐一讲解每种模式的适用场景,并通过时序图拆解其流程。 关键参数说明:
- client_id:客户端的唯一标识,用于让授权服务器识别客户端(公开传输,无需保密)。
- client_secret:客户端的密钥,用于验证客户端的身份(仅在客户端与授权服务器之间传输,需严格保密)。
- response_type=code:表示客户端请求的是授权码。
- redirect_uri:授权完成后,授权服务器将用户重定向回客户端的地址(需提前在授权服务器注册,防止恶意跳转)。
- scope:客户端请求的资源范围(如“获取用户昵称和头像”“获取用户邮箱”)。
- refresh_token:可选参数,用于当访问令牌过期时,无需用户再次授权,直接通过刷新令牌获取新的访问令牌。
2.1 授权码模式(Authorization Code Grant)——最常用、最安全
适用场景
客户端拥有自己的服务器(如Web应用、后端服务),能够安全存储“客户端密钥”,且可以接收授权服务器的回调请求。这是绝大多数第三方登录场景的首选模式,例如:Web版GitHub登录第三方网站、企业邮箱登录第三方办公系统等。
核心流程时序图
sequenceDiagram
participant U as 资源所有者(用户)
participant C as 客户端(第三方应用)
participant S as 授权服务器
participant Z as 资源服务器
U ->>C : 发起授权请求<br/>(如点击“使用GitHub登录”)
C ->>S: 重定向至授权<br/>服务器,携带参数:<br/>client_id、redirect_uri、<br/>response_type=code、scope
S->>U: 验证用户身份(如让用户输入GitHub账号密码),<br/>并询问是否同意授权
U-->>S: 同意授权
S->>C: 重定向至client<br/>指定的redirect_uri,携带授权码code
C ->>S: 向授权服务器请求访问令牌,携带参数:<br/>client_id、client_secret、code、<br/>grant_type=authorization_code、redirect_uri
S->>C: 验证client_id、client_secret、code的有效性,<br/>发放访问令牌access_token<br/>(可选刷新令牌refresh_token)
C->>U: 携带access_token向<br/>资源服务器请求资源
S->>C: 验证access_token有效性,返回对应的资源
C->>Z: 向用户展示获取到的资源(如完成登录、显示个人信息)
流程说明
授权码模式的核心是“通过授权码间接获取访问令牌”,而非直接获取,这一设计避免了访问令牌在浏览器中传输,降低了泄露风险。
2.2 简化模式(Implicit Grant)——无后端客户端专用
适用场景
客户端是无后端的纯前端应用(如Vue、React开发的单页应用SPA、原生移动应用),无法安全存储“客户端密钥”(前端代码易被破解,密钥可能泄露)。该模式直接将访问令牌返回给客户端,省略了授权码步骤。
核心流程时序图
sequenceDiagram
participant 资源所有者(用户)
participant 客户端(纯前端应用)
participant 授权服务器
participant 资源服务器
资源所有者(用户)->>客户端(纯前端应用): 发起授权请求<br/>(如点击“使用微信登录”)
客户端(纯前端应用)->>授权服务器: 重定向至授权服务器,<br/>携带参数:client_id、redirect_uri、<br/>response_type=token、scope
授权服务器->>资源所有者(用户): 验证用户身份,询问是否同意授权
资源所有者(用户)->>授权服务器: 同意授权
授权服务器->>客户端(纯前端应用): 重定向至redirect_uri,<br/>将access_token<br/>通过URL哈希(井号)<br/>传递给客户端
客户端(纯前端应用)->>资源服务器: 携带access_token向<br/>资源服务器请求资源
资源服务器->>客户端(纯前端应用): 验证access_token<br/>有效性,返回资源
客户端(纯前端应用)->>资源所有者(用户): 向用户展示资源<br/>(如完成登录)
流程说明
简化模式的核心是“直接返回访问令牌”,response_type=token表示客户端直接请求访问令牌。由于访问令牌通过URL哈希传递(哈希部分仅在浏览器端处理,不会发送到客户端服务器),一定程度上降低了泄露风险,但仍不如授权码模式安全。此外,该模式不支持刷新令牌(因无法安全存储),访问令牌过期后需用户重新授权。
2.3 密码模式(Resource Owner Password Credentials Grant)——信任场景专用
适用场景
客户端与资源服务提供商之间存在高度信任关系(如同一公司的产品),且用户愿意向客户端提供自己的账号密码。例如:某公司的内部管理系统(客户端),需要获取用户在公司统一认证平台(资源服务提供商)的资源,用户可直接向管理系统输入统一认证平台的账号密码。 注意:该模式需要用户向客户端泄露账号密码,风险较高,仅适用于高度信任的场景,非必要不使用。
核心流程时序图
sequenceDiagram
participant 资源所有者(用户)
participant 客户端(信任的应用)
participant 授权服务器
participant 资源服务器
资源所有者(用户)->>客户端(信任的应用): 向客户端提供自己的<br/>账号(username)<br/>和密码(password)
客户端(信任的应用)->>授权服务器: 向授权服务器请<br/>求访问令牌,<br/>携带参数:<br/>grant_type=password、<br/>username、<br/>password、client_id、<br/>client_secret
授权服务器->>客户端(信任的应用): 验证账号密码<br/>及客户端身份,<br/>发放access_token<br/>(可选refresh_token)
客户端(信任的应用)->>资源服务器: 携带access_token请求资源
资源服务器->>客户端(信任的应用): 验证token有效性,返回资源
客户端(信任的应用)->>资源所有者(用户): 向用户展示资源
流程说明
密码模式的核心是“客户端使用用户的账号密码直接向授权服务器换取访问令牌”。由于用户账号密码直接暴露给客户端,该模式仅适用于客户端完全可信的场景(如企业内部系统),禁止在公开的第三方应用中使用。
2.4 客户端凭证模式(Client Credentials Grant)——客户端自身授权
适用场景
无需用户参与,客户端以自身的身份向授权服务器请求访问令牌,用于访问客户端自身的资源(而非用户的个人资源)。例如:某第三方应用需要访问微信开放平台的“接口调用统计”资源(属于应用自身的资源,与具体用户无关)。
核心流程时序图
sequenceDiagram
participant 客户端(第三方应用)
participant 授权服务器
participant 资源服务器
客户端(第三方应用)->>授权服务器: 向授权服务器<br/>请求访问令牌,<br/>携带参数:<br/>grant_type=<br/>client_credentials、<br/>client_id、client_secret
授权服务器->>客户端(第三方应用): 验证client_id和<br/>client_secret<br/>的有效性,发放<br/>access_token
客户端(第三方应用)->>资源服务器: 携带access_token请求客户端自身的资源
资源服务器->>客户端(第三方应用): 验证token有效性,返回资源
流程说明
客户端凭证模式的核心是“客户端以自身身份授权”,无资源所有者参与。该模式适用于客户端访问自身资源的场景,访问令牌的权限范围仅限于客户端自身,与用户无关。
2.5 刷新令牌模式(Refresh Token Grant)——令牌过期续签
适用场景
不属于独立的授权模式,而是对上述四种模式的补充。由于OAuth 2.0的访问令牌通常有较短的有效期(为了降低泄露风险),当访问令牌过期时,通过刷新令牌可以无需用户再次授权,直接获取新的访问令牌。
核心流程时序图
sequenceDiagram
participant 客户端
participant 授权服务器
participant 资源服务器
客户端->>资源服务器: 携带过期的access_token请求资源
资源服务器->>客户端: 返回token过期错误(如401 Unauthorized)
客户端->>授权服务器: 向授权服务器<br/>请求新的access_token,<br/>携带参数:<br/>grant_type=refresh_token、<br/>refresh_token、client_id、<br/>client_secret
授权服务器->>客户端: 验证refresh_token<br/>有效性,发放新的access_token<br/>(可选新的refresh_token)
客户端->>资源服务器: 携带新的access_token请求资源
资源服务器->>客户端: 验证token有效性,返回资源
流程说明
刷新令牌的有效期通常较长,且仅在客户端与授权服务器之间传输,安全性较高。当访问令牌过期时,客户端通过刷新令牌自动续签,避免了用户频繁重新授权,提升了用户体验。需要注意的是,若刷新令牌泄露,攻击者可能会持续获取新的访问令牌,因此刷新令牌也需严格保密。
三、OIDC(OpenID Connect):基于OAuth 2.0的身份认证协议
在实际应用中,很多场景不仅需要“授权”(允许第三方应用访问资源,但不能确定是谁在使用第三方应用访问资源),还需要“认证”(确认用户的身份,获取用户详细信息)。OAuth 2.0本质上是一个授权协议,无法直接提供完整的身份认证能力。而OIDC(OpenID Connect)作为基于OAuth 2.0的身份认证层,完美解决了这一问题,它在OAuth 2.0的基础上增加了身份认证相关的规范,让第三方应用能够安全地获取用户的身份信息。
3.1 OIDC与OAuth 2.0的关系
OIDC并非替代OAuth 2.0,而是在OAuth 2.0的框架上进行扩展:
- OAuth 2.0的核心是“授权”,解决的是“第三方应用能否访问用户资源”的问题;
- OIDC的核心是“认证+授权”,在OAuth 2.0授权流程的基础上,额外提供了用户身份信息的标准化传输方式,解决的是“第三方应用如何确认用户身份”的问题。 简单来说,OIDC = OAuth 2.0 + ID Token(身份令牌)。OIDC通过在OAuth 2.0的授权流程中新增“ID Token”,让客户端能够直接获取用户的身份信息(如用户ID、用户名、邮箱等),实现身份认证。
3.2 OIDC的核心概念
- ID Token(身份令牌):OIDC的核心凭证,是一个JWT(JSON Web Token)格式的令牌,包含用户的身份信息(如sub:用户唯一标识、name:用户名、email:邮箱等)。ID Token由授权服务器签发,客户端可通过验证ID Token的签名来确认其真实性,从而完成用户身份认证。
- UserInfo端点:授权服务器提供的一个HTTP端点,客户端可携带OAuth 2.0的访问令牌(Access Token)向该端点请求更详细的用户身份信息。ID Token通常包含基础身份信息,若客户端需要更丰富的信息,可通过UserInfo端点获取。
- OpenID Provider(OP):提供OIDC服务的实体,本质上是增强版的OAuth 2.0授权服务器,负责用户身份认证、签发ID Token和Access Token。例如,微信、QQ、GitHub等提供第三方登录的平台,都可以作为OIDC中的OP。
- Relying Party(RP):依赖OP进行身份认证的客户端应用,即原OAuth 2.0中的“客户端”。例如,使用微信登录的游戏APP就是RP,它依赖微信(OP)完成用户身份认证。
3.3 OIDC的核心流程(基于授权码模式扩展)
OIDC的核心流程基于OAuth 2.0的授权码模式扩展而来,新增了获取和验证ID Token的步骤,具体时序如下:
sequenceDiagram
participant 资源所有者(用户)
participant RP(客户端应用)
participant OP(OpenID Provider)
participant 资源服务器
资源所有者(用户)->>RP(客户端应用): 发起登录请求(如点击“使用微信登录”)
RP(客户端应用)->>OP(OpenID Provider): 重定向至OP,携带参数:client_id、redirect_uri、response_type=code、scope=openid+profile+email(scope含openid表示启用OIDC)
OP(OpenID Provider)->>资源所有者(用户): 验证用户身份(如输入账号密码),询问是否同意授权
资源所有者(用户)->>OP(OpenID Provider): 同意授权
OP(OpenID Provider)->>RP(客户端应用): 重定向至redirect_uri,携带授权码code
RP(客户端应用)->>OP(OpenID Provider): 向OP请求令牌,携带参数:client_id、client_secret、code、grant_type=authorization_code、redirect_uri
OP(OpenID Provider)->>RP(客户端应用): 验证通过后,返回Access Token、ID Token(核心新增)、可选Refresh Token
RP(客户端应用)->>RP(客户端应用): 验证ID Token的签名和有效性(确认用户身份)
RP(客户端应用)->>OP(OpenID Provider): 携带Access Token访问UserInfo端点,请求详细用户信息
OP(OpenID Provider)->>RP(客户端应用): 返回用户详细身份信息
RP(客户端应用)->>资源服务器: 携带Access Token请求资源(授权流程,同OAuth 2.0)
资源服务器->>RP(客户端应用): 验证Token有效性,返回资源
RP(客户端应用)->>资源所有者(用户): 完成登录,展示用户信息和资源
3.4 OIDC的核心优势
- 标准化身份认证:OIDC定义了统一的身份信息传输格式(ID Token)和交互流程,解决了不同平台身份认证方式不统一的问题,让跨平台单点登录(SSO)更容易实现。
- 基于OAuth 2.0,兼容性强:OIDC完全基于OAuth 2.0扩展,原有支持OAuth 2.0的系统只需少量改造即可支持OIDC,降低了升级成本。
- 安全性高:ID Token采用JWT格式,包含签名信息,客户端可通过验证签名确认Token的真实性,避免身份信息被篡改;同时,用户身份信息无需通过账号密码直接传输,降低了泄露风险。
四、总结
OAuth 2.0的核心价值在于“安全的授权”——通过分离“认证”与“授权”,在不泄露用户账号密码的前提下,实现第三方应用对用户资源的可控访问。其4个核心角色(资源所有者、客户端、授权服务器、资源服务器)构成了授权流程的基础,而5种授权模式则针对不同场景提供了灵活的解决方案:
- 授权码模式:最安全、最常用,适用于有后端的客户端;
- 简化模式:适用于无后端的纯前端/移动客户端,直接返回访问令牌;
- 密码模式:适用于高度信任的场景,用户需向客户端提供账号密码;
- 客户端凭证模式:适用于客户端访问自身资源的场景,无用户参与;
- 刷新令牌模式:补充模式,用于访问令牌过期后自动续签。
而OIDC作为基于OAuth 2.0的身份认证层,补齐了OAuth 2.0在身份认证上的短板,通过新增ID Token实现了“认证+授权”一体化。在实际应用中,若场景需要确认用户身份(如第三方登录、单点登录),应优先选择OIDC;若仅需单纯的资源授权(如第三方应用调用API获取数据),使用OAuth 2.0即可。同时,无论是使用OAuth 2.0还是OIDC,都需严格遵守协议规范,妥善保管各类令牌和密钥,保障系统安全。