怎样给面试官通俗易懂的讲解oauth2.0中的授权码模式 注意:要使用QQ登录博客园的例子
好的,授权码模式是OAuth 2.0四种模式中最安全、最常用的一种。下面我用“QQ登录博客园”这个你熟悉的场景,分四步讲清楚。
先打个比方:就像“开支票”
在讲流程之前,先打个比方帮你建立直觉。
假设你想让朋友帮你去银行取1000块钱,但你不可能把银行卡密码告诉他。正确的做法是:你开一张1000元的支票给他,他拿着支票去银行,银行验证支票是真的,就把钱给他。
OAuth 2.0的授权码模式,干的就是类似的事:
- 你 = 用户(资源所有者)
- 朋友 = 博客园(第三方应用)
- 银行 = QQ(授权服务器 + 资源服务器)
- 支票 = 授权码(code)
- 银行最终给的钱 = 访问令牌(access_token)
四步走:QQ登录博客园完整流程
第一步:博客园把你“踢”到QQ去
你在博客园登录页,点击“QQ登录”按钮。
这时候,博客园的服务器会生成一个特殊的链接,让你的浏览器跳转到QQ的授权页面。这个链接里带了三个关键信息:
client_id:博客园在QQ互联平台注册时拿到的“身份证号”,告诉QQ“我是博客园”redirect_uri:QQ授权成功后该把用户送回博客园的哪个地址(回调地址)response_type=code:告诉QQ“我要用授权码模式”
对应标准流程的步骤(A) :客户端将用户导向认证服务器。
第二步:你在QQ页面登录并授权
浏览器跳转到QQ的登录页面后,你输入QQ号和密码,登录QQ。
登录成功后,QQ会问你:“博客园想要获取你的昵称和头像,你同意吗?”你点击“同意授权”。
对应标准流程的步骤(B) :用户登录并同意授权。
第三步:QQ给你一个“授权码”,把你送回博客园
你同意授权后,QQ的服务器会做两件事:
- 生成一个授权码(code) ——这就是那张“支票”
- 把你的浏览器重新导向回博客园,并且在网址后面带上这个授权码,比如:
https://www.cnblogs.com/callback?code=ABC123
注意:这个授权码有几个特点:
- 只能用一次,用过就失效
- 有效期很短(QQ规定10分钟内有效)
- 它不是最终访问用户信息的令牌,只是一张“换票凭证”
对应标准流程的步骤(C) :授权服务器生成授权码,通过回调地址返回给客户端。
第四步:博客园后台拿授权码去QQ换“访问令牌”
现在浏览器已经回到博客园页面了,但真正的授权还没完成。
博客园的前端页面只是一个“展示层”,接下来最关键的一步在博客园的后台服务器上发生:
- 博客园的后台拿到浏览器传过来的授权码
ABC123 - 博客园后台偷偷地(不经过浏览器)向QQ的服务器发一个请求,说:“我是博客园,这是我的
client_id和client_secret(密码),我手里有用户给的授权码ABC123,请给我访问令牌” - QQ服务器验证授权码有效、验证博客园身份无误后,返回一个访问令牌(access_token) 给博客园后台
对应标准流程的步骤(D)和(E) :客户端用授权码向授权服务器申请令牌,拿到令牌。
拿到了令牌,然后呢?
博客园拿到访问令牌后,就可以用这个令牌去QQ的资源服务器请求用户信息了——比如你的QQ昵称、头像等。
拿到这些信息后,博客园就知道“哦,原来是用户小明用QQ登录了”,于是帮你在博客园创建一个账号或者直接登录成功。
总结:为什么要搞得这么复杂?
你可能觉得绕了一大圈,为什么不直接让博客园拿你的QQ号和密码去查?
核心原因就一个:安全。
如果博客园直接拿你的QQ密码,万一博客园被黑客攻击,你的QQ密码就泄露了。而用授权码模式:
- 你的QQ密码只在QQ的页面上输入,博客园从头到尾都接触不到
- 授权码通过浏览器传递,但真正的令牌是在后台服务器之间交换的,不会暴露在浏览器里
- 你可以控制授权范围(比如只给昵称头像,不给好友列表)
- 令牌有过期时间,而且可以随时撤销
这就是为什么你在各大网站看到的“QQ登录”“微信登录”“GitHub登录”,背后用的都是这套授权码模式。
面试时可以这样一句话总结
“授权码模式就像先用一张临时支票(授权码)换真正的取款凭证(访问令牌) ,而不是直接把银行卡密码(QQ密码)交给第三方。QQ登录博客园就是典型:博客园把你导向QQ授权页,你登录同意后QQ给你一个code,博客园后台再用这个code去QQ换token,最后用token拿你的信息。整个过程你的密码始终只给QQ,博客园拿不到。”
这个问题问得很精准,说明你在思考实际落地的细节。
是不是用户每次请求都会携带上accesstoken
答案是:“不是”所有浏览器发起的请求都带,但“所有需要访问用户私有资源”的请求,都必须带。
为了让你在面试时讲清楚,我把“带不带”拆成三种场景,你一听就明白了:
1. 哪些“请求”绝对不带?
用户纯浏览公开内容时,不带。
比如你登录博客园之后,去看一篇不需要登录的技术文章。这个请求是浏览器直接向博客园的Web服务器发起的,目的是拿HTML页面。这个请求里没有Access Token,因为博客园只需要返回公开的网页内容,不需要知道你是谁。
2. 哪些“请求”必须带?
前端(浏览器)调用后端API接口时,必须带。
比如你在博客园登录后,想修改自己的个人简介,或者查看“我的收藏”。此时,博客园的前端代码(JavaScript)会向后端API发一个Ajax请求(比如 GET /api/myinfo)。
这个请求必须带上Access Token,通常放在 HTTP请求头(Header) 里,像这样:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...(你的token)
因为博客园的后端服务器不认识你的浏览器了(HTTP是无状态的),它必须靠这个Token来验证:“这个请求确实是QQ那边认证过的用户小明发来的”。
面试加分点:你可以强调,绝对不会放在URL参数里(比如
?token=xxx),因为浏览器地址栏、历史记录和服务器日志都会暴露Token,极不安全。标准做法是放在Header中。
3. “每次”的边界是什么?(Token过期了怎么办?)
既然每次调用接口都要带,那如果Token过期了,用户岂不是每隔一小时就要重新输一遍QQ密码?
实际情况是这样处理的:
- 博客园拿到QQ给的
access_token时,同时还会拿到一个refresh_token(刷新令牌)。 access_token有效期短(比如1小时),refresh_token有效期长(比如30天)。- 当用户操作时,博客园后台发现“咦,这个Token过期了”,它会自动拿着
refresh_token去QQ那里换一个新的access_token,然后后端拿着新Token去处理用户的请求。 - 对用户来说,他完全无感知,只需要在浏览器里正常点击“保存个人简介”即可。
用“QQ登录博客园”的例子串一遍:
- 登录时:你授权后,博客园后台拿到了Token,存起来(存到Session里,或者返回给前端存到内存/本地存储里)。
- 你在博客园写评论:你的浏览器发请求给博客园后端,带上Token。后端看到Token,知道是你,于是保存这条评论。
- 你在博客园看首页推荐:浏览器请求只是拿HTML,不带Token,因为看推荐不需要知道你是谁。
- 你一小时后修改头像:浏览器带上过期的Token去请求,博客园后台发现过期,自动用refresh_token换新Token,然后继续帮你改头像。整个过程你甚至不知道Token换过一次。
面试时一句话总结:
“Access Token不是像Cookie那样每个网页请求都自动携带,而是只在客户端(浏览器/App)调用需要用户身份认证的后端API接口时,主动放在HTTP请求头里带过去。 不带Token的只用于获取公开数据,而Token过期则通过Refresh Token静默刷新,所以用户感觉不到‘每次’携带的负担。”
浙公网安备 33010602011771号