# Identity Server

## 目录 <a href="#mu-lu" id="mu-lu"></a>

* OAuth 2.0
* OpenID Connect
* QuickStart

### OAuth 2.0 <a href="#oauth-20" id="oauth-20"></a>

* 概念
* 过程
* 通信
* 组件
* 示例代码

#### 概念 <a href="#gai-nian" id="gai-nian"></a>

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2F4AqFE5jBaPvCOxmt1IDI%2F243.jpg?alt=media\&token=c1f5c77e-4d46-4a58-8225-3abf2a8b9ac5)

OAuth 2.0 是一个授权协议，它允许软件应用代表（而不是充当）资源拥有者去访问资源拥有者的资源（如何让一个系统组件获取另一个系统组件的访问权限）

* 受保护的资源：是资源拥有者有权限访问的组件
* 资源拥有者：有权访问 API，并能将 API 访问权限委托出去
* 客户端：凡是使用了受保护资源上的 API，都是客户端

#### 过程 <a href="#guo-cheng" id="guo-cheng"></a>

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FakPXETjyoRaRNdC1t3um%2F244.jpg?alt=media\&token=2f77a0e5-1dde-43cd-8c17-91b50e9f59af)

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2Fdunn3a0QmGIAjUZT0qxp%2F245.jpg?alt=media\&token=cd93fa5c-6517-49cb-afc0-4c52b6335fe3)

#### 通信 <a href="#tong-xin" id="tong-xin"></a>

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FEtz3fEiln6JEUcQK9atZ%2F246.jpg?alt=media\&token=aec0258c-4d7c-48b8-b1f5-0fe68001284b)

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FyXXD2iZtTV2IZYKZhGPN%2F247.jpg?alt=media\&token=ce4dbf85-4989-44ff-bd56-54b0be86bbd2)

#### 组件 <a href="#zu-jian" id="zu-jian"></a>

* 访问令牌 token
* 权限范围 scope
* 刷新令牌 refresh token
* 授权许可 grant\_type

| grant\_type              | 授权方式    | 授权前置条件 | 使用通信信道 | 说明                          |
| ------------------------ | ------- | ------ | ------ | --------------------------- |
| authorization\_code/PKCE | 授权码模式   | 授权码    | 前端/后端  | 客户端通过code在后端与授权服务器进行交互获取令牌  |
| implict（不建议使用）           | 简化模式    |        |        |                             |
| password（不建议使用）          | 密码模式    | 用户名/密码 | 后端     | 在客户端输入用户名和密码，由客户端向授权服务器获取令牌 |
| client\_credentials      | 客户端模式   | 无      | 后端     |                             |
| device\_code             | 设备码     |        |        |                             |
| refresh\_token           | 刷新token |        |        | 用refresh\_token来换取新的token   |

**授权码模式**

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FWoVMjB6THb1bIn7OloWc%2F248.jpg?alt=media\&token=2ca75a27-3990-4e71-84c4-1652cc8c2d62)

1. 第三方应用首先向服务提供商申请 client\_id 应用唯一标识、Client\_secret 密钥，用于后续获取令牌时提供身份校验
2. 申请授权码：此时要提供预分配好的 client\_id 标识来源，提供 scope 标识要申请的权限，提供 redirect\_uri 标识授权完毕后要回跳的第三方应用链接
3. 第一次 302 重定向：认证服务器展示登录授权页
4. 第二次 302 重定向：在用户提交授权，认证服务器认证成功后，会分配授权码 code，并重定向回第三方应用的 redirect\_uri
5. （建议第三方应用要根据当前用户会话生成随机且唯一的 state 参数，并且收到授权码时先进行校验，避免 CSRF 攻击）最后，第三方应用会向认证服务器申请令牌 access\_token，此时要提供预分配好的 code、client\_id、client\_secret 以便认证。这一步是在后端之间完成的，对用户不可见。access\_token 是有有效期的，过期后需要刷新
6. 拿到令牌 access\_token 后，第三方应用就可以访问资源方，获取所需资源 access\_token 相当于用户的 session id

**选择正确的许可类型**

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FBsWDc5l6W9Oo4AyakfVh%2F249.jpg?alt=media\&token=b819f5a3-23c3-4313-9c84-2a15a5a38979)

#### 示例代码 <a href="#shi-li-dai-ma" id="shi-li-dai-ma"></a>

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2F6tZnGsseF4l0pX1bZagQ%2F250.jpg?alt=media\&token=902c6119-6cbc-4019-ba19-ee1a444c60a2)

地址：<https://github.com/skoruba/IdentityServer4.Admin>

### OpenID Connect <a href="#openid-connect" id="openid-connect"></a>

* OAuth2.0 的不足之处
* OIDC 概念

#### OAuth2.0 的不足之处 <a href="#oauth20-de-bu-zu-zhi-chu" id="oauth20-de-bu-zu-zhi-chu"></a>

OAuth2.0 中的 access\_token 就是酒店的房卡，谁都可以拥有房卡，有房卡就可以打开酒店的门，但是房卡上并没有当前使用房卡的用户信息，如果需要知道当前房卡所有人的信息需要单独再向酒店的前台去询问

#### OIDC 概念 <a href="#oidc-gai-nian" id="oidc-gai-nian"></a>

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FH00S4w05DkhHgeOeEtpk%2F251.jpg?alt=media\&token=19ad57de-20ea-4b9e-b3b0-420ecf7c2a09)

Open ID Connect 1.0 是建立在 OAuth 2.0 之上的一个身份层

<https://openid.net/specs/openid-connect-core-1_0.html#ImplicitAuthorizationEndpoint>

### QuickStart <a href="#quickstart" id="quickstart"></a>

安装模板

```
dotnet new -i IdentityServer4.Templates
```

查看模板

```
dotnet new
```

使用模板创建

```
dotnet new is4inmem -n QuickStart

已成功创建模板“IdentityServer4 with In-Memory Stores and Test Users”。
```

打开项目，启动

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FSS9DOOip4Ijn29u7ES4Y%2F252.jpg?alt=media\&token=540e92e0-f5b2-44d3-a0f3-b0fee7029390)

点击进入登录页面，使用默认用户登录

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FEciguo2r1aYpt9Rm2fIK%2F253.jpg?alt=media\&token=b4599c6a-4c9d-4428-a2c5-3f1ed1a4d8a0)

登录结果

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2FE0XlIfP0pi2pPnYG5nJq%2F254.jpg?alt=media\&token=075bae06-85e3-4ed1-b098-588bc01ccd89)

根据配置文件通过ClientCredentials的方式获取token

```
// m2m client credentials flow client
new Client
{
    ClientId = "m2m.client",
    ClientName = "Client Credentials Client",

    AllowedGrantTypes = GrantTypes.ClientCredentials,
    ClientSecrets = { new Secret("511536EF-F270-4058-80CA-1C89C192F69A".Sha256()) },

    AllowedScopes = { "scope1" }
},
```

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2F1SrXedOknZuRbNwSjuw2%2F255.jpg?alt=media\&token=a035f7f6-e5e9-4bc5-9b98-2cc4b53866f9)

根据配置文件通过Code的方式获取token

```
// interactive client using code flow + pkce
new Client
{
    ClientId = "interactive",
    ClientSecrets = { new Secret("49C1A7E1-0C79-4A89-A3D6-A37998FB86B0".Sha256()) },
    
    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = false,
    AllowPlainTextPkce = true,

    RedirectUris = { "https://localhost:44300/signin-oidc" },
    FrontChannelLogoutUri = "https://localhost:44300/signout-oidc",
    PostLogoutRedirectUris = { "https://localhost:44300/signout-callback-oidc" },

    AllowOfflineAccess = true,
    AllowedScopes = { "openid", "profile", "scope2" }
},
```

访问认证接口获取授权码

```
https://localhost:5001/connect/authorize?client_id=interactive&scope=openid&response_type=code&redirect_uri=https://localhost:44300/signin-oidc&nonce=xyz
```

返回授权码

```
https://localhost:44300/signin-oidc?code=BC56FE53D39BD46A5D55D43F485E23D7FF6583FEDD7A2A0B7A2A3DFDF5C52935&scope=openid&session_state=SwfB-jWoQ16C67cm5c_ANqbVE1R50Krj55GuJuArEQ0.BE30A11CD461DC430C5121AEFB4A4E82
```

![](https://3083743005-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8gwpNo3eyzHkX0O40HRA%2Fuploads%2F0xTYU3KI0xR3W7TmyJhG%2F256.jpg?alt=media\&token=0345aede-2340-4187-8c94-d8fef718f257)
