IdentityServer4源码解析_4_令牌发放接口
holdengong 人气:0
# 目录
- [identityserver4源码解析_1_项目结构](https://holdengong.com/identityserver4源码解析_1_项目结构)
- [identityserver4源码解析_2_元数据接口](https://holdengong.com/identityserver4源码解析_2_元数据接口)
- [identityserver4源码解析_3_认证接口](https://holdengong.com/identityserver4源码解析_3_认证接口)
- [identityserver4源码解析_4_令牌发放接口](https://holdengong.com/identityserver4源码解析_4_令牌发放接口)
- [identityserver4源码解析_5_查询用户信息接口](https://holdengong.com/identityserver4源码解析_5_查询用户信息接口)
- [identityserver4源码解析_6_结束会话接口](https://holdengong.com/identityserver4源码解析_6_结束会话接口)
- [identityserver4源码解析_7_查询令牌信息接口](https://holdengong.com/identityserver4源码解析_7_查询令牌信息接口)
- [identityserver4源码解析_8_撤销令牌接口](https://holdengong.com/identityserver4源码解析_8_撤销令牌接口)
# 协议
## Token接口
oidc服务需要提供token接口,提供AccessToken,IdToken,以及RefreshToken(可选)。在授权码模式下,token接口必须使用https。
## 请求
必须使用POST方法,使用x-www-form-urlencoded序列化参数,clientId:clientSecret使用Basic加密放在Authorization头中
```http
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
```
## 请求校验
认证服务必须校验下列内容:
- 验证client是否颁发了秘钥
- 验证为该客户端颁发了授权码
- 验证授权码有效性
- 如果可能的话,验证授权码是否被使用过
- 验证redirect_uri 与发起认证请求时的值一致
## 成功响应
在收到token请求,并校验通过之后,认证服务返回成功报文,报文包含了身份令牌和通行令牌。数据格式使用application/json。token_type必须返回Bearer,其他类型token不在本协议范围内。在OAuth2.0响应报文基础上,oidc增加了id_tken。所有token包含了token或者其他敏感信息的响应报文,必须包含以下响应头。
```http
Cache-Control no-store
Pragma no-cache
```
## 失败响应
如果认证失败返回application/json格式错误消息,状态码400
```http
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"error": "invalid_request"
}
```
## id token校验
客户端必须校验返回的id token, 校验条件如下。对照这些条件,就可以更懂Microsoft.Authentication.OpenIdConnect里面的代码了,要做的事情很多。
1. 如果id token被加密,使用客户端注册时候约定的秘钥和算法解密。如果约定了加密方式,id token未被加密,客户端应该拒绝。
2. 签发方标识必须与iss声明一致
3. 客户端必须校验aud声明包含了它的客户端id,如果id token未返回正确的audience或者反悔了不被新人的audience,应该拒绝
4. 如果id token包含多个audience,需要校验是否有azp声明。azp即Authorized party,标识被授权的client。
5. 如果包含azp声明,客户端需要校验其值是否为自己的客户端id
6. 如果id token由token接口直接颁发给客户端(授权码模式就是如此),客户端必须根据alg参数值的算法验证签名。客户端必须使用签发方提供的秘钥。
7. alg值默认为RS256,客户端可以在注册的时候使用id_token_signed_response_alg参数指定配置。
8. 如果jwt的alg头使用了基于mac地址的加密算法,如HS256, HS384,HS512,aud声明中的字节会用作验签。(意思是会把mac地址相关信息写在aud声明上?)
9. The current time MUST be before the time represented by the exp Claim.
当前时间必须早于exp(token过期时间)。
10. iat(签发时间)可以用于拒绝过早、或者过于频繁签发的token,可以用于预防重放攻击。可接受时间范围由客户端自行决定。
11. 如果认证请求包含了nonce参数,客户端必须交验认证响应中返回的nonce值是否一致。防止重放攻击。
12. 如果客户端请求了acr声明(Authentication Context Class Reference,认证会话上下文,用于表示当前认证会话),必须交验acr值是否合法。
13. 如果客户端请求了auth_time声明,客户端应该校验认证时间是否已经超出,是否需要重新认证。
## access token校验
如果id_token中包含了at_hash声明,需要做下面的校验。at_hash标明了access_token和id_token之间的会话关联关系,做这个校验可以防跨站伪造。
1. 用idtoken的alg头标明的算法加密access_token,比如alg位RS256,则是用HSA-256算法加密。
2. 取hash值左边一般使用base64url加密
3. id token中的at_hash值必须跟上个步骤得到的值一致
校验规则很多,了解一下即可,绝大部分属于客户端需要做的部分,绝大部分跟安全有关。这一块的实现可以参考Microsoft.Authentication.OpenIdConnect,这是客户端的实现。我们现在看的IdentityServer是认证服务端的实现。
# 源码
## 五种授权模式
有下面几种授权模式可以请求token接口
- 授权码模式:最常用的code换token
- 混合模式:混合模式是授权码模式+简化模式混合使用的方式,在用授权码code找token接口换通行/身份令牌的逻辑与授权码模式的逻辑是一样的。idsv4中,混合模式没有自己的单独实现,只是把授权码+简化模式的代码同时调用。
- 客户端密钥模式:一般用于完全信任的内部系统,密钥换取access_token,由于没有用户参与,scope包含open_id是非法的
- 用户名密码模式:一般用于第三方对接、无界面交互场景。即username+password换token/id_token,password不一定是密码,也可以是验证码或其他的什么东西,这个完全取决于开发自己的实现
- 设备流模式(略)
**注意:简化模式所有的token都是由认证接口(authorize)一次性返回的,不能使用token接口。**
## 校验请求方法
token接口仅允许POST方法,Content-Type必须为application/x-www-form-urlencoded,否则抛出InvalidRequest错误。
```csharp
public async Task
加载全部内容