> For the complete documentation index, see [llms.txt](https://authing.gitbook.io/authing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://authing.gitbook.io/authing/authentication/use-saml/configure-authing-as-sp-and-idp.md).

# 同时使用 Authing 作为 SP 和 IdP

本教程讲述如何使用 Authing 云上的 SAML SP 和 SAML IdP 为企业或个人快速接入单点认证能力。完成本教程后，你会拥有运行在 Authing 云上的 SAML Service Provider 和 SAML Identity Provider 来处理 SAML 协议相关的过程，而你只需关注 Authing 返回的用户信息与 JWT Token。

在用户访问受保护的资源时，结合 Authing SDK 可以对他携带的 JWT Token 进行验证。如果 JWT Token 验证失败，只需将用户重定向到 SAML Service Provider 的云上地址，它会负责通过 SAML 协议与 IdP 交换信息从而认证用户，并返回 JSON 格式的用户信息。

## 创建一个 SAML IdP 应用

进入应用控制台 -> 第三方登录 -> SAML IdP 选项卡，点击「创建 SAML IdP」

填写应用信息，为云上的 IdP 指定一个二级域名，点击「确定」

此时我们还没有 SP，所以 AssertionConsumeServiceURL 可以先不填写真正的 appId。

![](/files/-LhEp3uXDe3J2HkyyYuq)

其他配置使用默认即可。

生成一对秘钥，上传。用来对 SAML Response 签名、验签。

![](/files/-LhEpQvo4MhlOTul9fEC)

![](/files/-LhEpXsykhQJAUlyDTNk)

创建完成后，转到使用方法页。记录 IdP 登录 URL、IdP 登出 URL 和 IdP EntityID，后续创建 SP 时会使用。

## 创建一个 SAML SP 应用

进入应用控制台 -> 第三方登录 -> 社会化登录，在 SAML Service Provider 区域，点击「+」。

![Authing 控制台](/files/-LxpcVMfTrAj5ieJdeJb)

![创建 SAML SP](/files/-LxpccWckvtaleZAg609)

填写应用信息，为云上的 SP 指定一个二级域名，点击「确定」 。

在 IdP 登录 URL、IdP 登出 URL、IdP EntityID 输入刚才记录的三项内容。

其他配置使用默认即可。点击「确定」。

在 IdP 字段映射方案列表中选择 Authing，点击「确定」。

创建完成后，转到使用方法页。记录 AssertionConsumeServiceURL、下载 SP Metadata。

![](/files/-LhEnm5qihW7RenMTfnt)

## 编辑刚创建的 IdP 应用

进入应用控制台 -> 第三方登录 -> SAML IdP 选项卡，找到刚刚创建的 IdP，点击右侧的「...」详情按钮，进入编辑。

![编辑 SAML IdP](/files/-LxpeNxSvaL45EZ83V7F)

在基础配置选项卡，填入刚才记录的 AssertionConsumeServiceURL、上传刚才下载的 SP Metadata，点击「确定」。

![填写基本信息](/files/-Lxpeh_yRTAP8izGhZYk)

在使用方法选项卡，下载 IdP Metadata。

![](/files/-Lxpeue6FxeVh07tKazh)

## 编辑刚创建的 SP 应用

进入应用控制台 -> 第三方登录 -> 社会化登录，在 SAML Service Provider 区域，找到刚才创建的 SP 应用，点击「编辑」。

![Authing 控制台](/files/-LxpcVMfTrAj5ieJdeJb)

![编辑 SAML SP](/files/-LxpfEaDj2eqgqk1EWO3)

在基础配置选项卡，上传刚才下载的 IdP Metadata。点击「确定」。

![上传 IdP Metadata](/files/-LxpfMcwBRRGlfj8UZxE)

## 开始使用

当你的受保护资源被访问时，需要先对用户身份进行认证，可以通过 Authing SDK 检验 JWT Token 的合法性。如果 token 不合法，可以将用户重定向到云上的 SAML SP，完成后续的用户身份认证流程，Authing 云上的 SAML SP 最终会携带着用户信息和 JWT Token 跳回在 SP 中设置的回调地址。

云上的 SAML SP 地址形式如下

让 SP 通过 GET 请求发送 SAML Request

```
GET https://<domain>.authing.cn/oauth/saml/sp/<appId>/spinitsso-redirect
```

让 SP 通过 POST 请求发送 SAML Request

```
GET https://<domain>.authing.cn/oauth/saml/sp/<appId>/spinitsso-post
```

{% hint style="info" %}
以下是一次完整的 SAML 登录流程
{% endhint %}

### 访问云上的 SP

在浏览器直接访问云上 SP 地址或者通过后端重定向到云上 SP 地址。

![直接在浏览器访问云上 SP](/files/-LhEtAneftzTAAHOcRtH)

### 跳转到 IdP 认证页

如果用户没有登录过，会被重定向到 IdP 用户登录认证页。

![IdP 在认证用户身份](/files/-LhEsCH1TyN_hmaESIo0)

### 用户进行登录

用户可以选择一种方式进行登录。

![用户进行登录](/files/-LhEsOjc300IYO9VQL0X)

![用户确权](/files/-LhEsZJcE2YVBZah0CWj)

### Authing 将用户信息发到回调地址

云上的 IdP 会将 SAML Response 发送到云上的 SP，SP 会处理好 SAML Response XML 信息，以 JSON 的数据格式将用户信息发到在 SP 配置的回调地址。

![](/files/-LhEsmJhZitfPMux6Q_p)

### 检验用户信息签名

以下是一个发送到回调地址数据的示例

```
https://authing.cn/?data=%7B%22_id%22%3A%225e1c31b00c9ba94f7e2b4046%22%2C%22email%22%3A%22asdf%40123.com%22%2C%22emailVerified%22%3Afalse%2C%22unionid%22%3A%22saml%7Cauthing%7Cauthing%7C5e1c31300c9ba94f7e2b4007%22%2C%22openid%22%3Anull%2C%22registerMethod%22%3A%22saml%3Aidp%3A%3Aauthing%22%2C%22username%22%3A%22asdfasdf%22%2C%22nickname%22%3A%22%22%2C%22company%22%3A%22%22%2C%22photo%22%3A%22https%3A%2F%2Fusercontents.authing.cn%2Fauthing-avatar.png%22%2C%22token%22%3A%22eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImVtYWlsIjoiYXNkZkAxMjMuY29tIiwidW5pb25pZCI6InNhbWx8YXV0aGluZ3xhdXRoaW5nfDVlMWMzMTMwMGM5YmE5NGY3ZTJiNDAwNyIsImlkIjoiNWUxYzMxYjAwYzliYTk0ZjdlMmI0MDQ2IiwiY2xpZW50SWQiOiI1ZTFjMmEzMzA4YTljNTQ1Y2IxZGMyZWEifSwiaWF0IjoxNTc4OTE3MjEyLCJleHAiOjE1ODAyMTMyMTJ9.3wAuO3Ql53ywaG9Wjm_sxfMlTaU8BnvQgwyJqPTz6n4%22%2C%22tokenExpiredAt%22%3A%222020-01-28T20%3A06%3A52%2B08%3A00%22%2C%22loginsCount%22%3A3%2C%22lastLogin%22%3A%222020-01-13T20%3A06%3A52%2B08%3A00%22%2C%22lastIP%22%3A%22127.0.0.1%22%2C%22signedUp%22%3A%222020-01-13T17%3A00%3A32%2B08%3A00%22%2C%22blocked%22%3Afalse%2C%22isDeleted%22%3Afalse%7D&signature=b84f601b8254251437f2f2ee650b64a1d16a14e6a1b6c397f3eef55abfa2cd6a&code=200&returnTo=
```

在 url 的 query 中有一个 signature 字段

```
signature=b84f601b8254251437f2f2ee650b64a1d16a14e6a1b6c397f3eef55abfa2cd6a
```

开发者需要检验这个字段是否合法来判断用户信息真实来自 Authing，而不是来自伪造的请求。

签名方式为 HMAC-SHA256，生成签名的伪代码如下：

```
signature = HMAC-SHA256(<SAML SP 应用 secret>, <用户信息 JSON 字符串>)
```

注意需要提**取出** url 中 **data** 字段，并进行 **unescape** 操作，将结果作为参数放在 <用户信息 JSON 字符串>。<用户信息 JSON 字符串> 中**不能有 % 等 url 中的转义字符，必须是一个 JSON 格式字符串**。

Node.JS 代码示例如下：

```javascript
let resultUrl = 'https://authing.cn/?data=%7B%22_id%22%3A%225e1c31b00c9ba94f7e2b4046%22%2C%22email%22%3A%22asdf%40123.com%22%2C%22emailVerified%22%3Afalse%2C%22unionid%22%3A%22saml%7Cauthing%7Cauthing%7C5e1c31300c9ba94f7e2b4007%22%2C%22openid%22%3Anull%2C%22registerMethod%22%3A%22saml%3Aidp%3A%3Aauthing%22%2C%22username%22%3A%22asdfasdf%22%2C%22nickname%22%3A%22%22%2C%22company%22%3A%22%22%2C%22photo%22%3A%22https%3A%2F%2Fusercontents.authing.cn%2Fauthing-avatar.png%22%2C%22token%22%3A%22eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImVtYWlsIjoiYXNkZkAxMjMuY29tIiwidW5pb25pZCI6InNhbWx8YXV0aGluZ3xhdXRoaW5nfDVlMWMzMTMwMGM5YmE5NGY3ZTJiNDAwNyIsImlkIjoiNWUxYzMxYjAwYzliYTk0ZjdlMmI0MDQ2IiwiY2xpZW50SWQiOiI1ZTFjMmEzMzA4YTljNTQ1Y2IxZGMyZWEifSwiaWF0IjoxNTc4OTE3MjEyLCJleHAiOjE1ODAyMTMyMTJ9.3wAuO3Ql53ywaG9Wjm_sxfMlTaU8BnvQgwyJqPTz6n4%22%2C%22tokenExpiredAt%22%3A%222020-01-28T20%3A06%3A52%2B08%3A00%22%2C%22loginsCount%22%3A3%2C%22lastLogin%22%3A%222020-01-13T20%3A06%3A52%2B08%3A00%22%2C%22lastIP%22%3A%22127.0.0.1%22%2C%22signedUp%22%3A%222020-01-13T17%3A00%3A32%2B08%3A00%22%2C%22blocked%22%3Afalse%2C%22isDeleted%22%3Afalse%7D&signature=b84f601b8254251437f2f2ee650b64a1d16a14e6a1b6c397f3eef55abfa2cd6a&code=200&returnTo='
let str = querystring.parse(url.parse(resultUrl).query).data


const hmac = crypto.createHmac('sha256', '75ff71126beb73236396aa74baa4195c');
hmac.update(str)
console.log(hmac.digest('hex') === querystring.parse(url.parse(resultUrl).query).signature)
```
