---
title: "Multipass"

doc_type: static
doc_category: static
doc_version: v20270301
source_url:
  html: 'https://developer.shopline.com/zh-hans-cn/docs/apps/multipass'
  md: 'https://developer.shopline.com/zh-hans-cn/docs/apps/multipass.md'
---
# Multipass
## 了解 Multipass
Multipass 登录适用于拥有单独网站和 SHOPLINE 商店的店主。它将用户从网站重定向到 SHOPLINE 商店，并使用他们用于注册原始网站的相同电子邮件地址或手机号无缝登录。如果还没有该电子邮件地址或手机号的帐户，则会用该电子邮件地址或手机号创建一个新账户。无需同步任何客户数据库。

---
## 如何使用 Multipass
### 在 SHOPLINE 中启用 Multipass 登录

1. 在 SHOPLINE admin 中，点击 **【设置】>【客户账户】>【客户账户类型】**。请先确保你已选择 **【经典客户账户】**。然后，找到 **【通过 Multipass 登录】**，点击 **【启用】**。

![image 22.png](https://s2cdn.myshopline.com/slfs/op-new/file/2023/12/22/555777/image22.png)

2. 启用后，将与你共享一个 **【加密密钥】**。你需要此密钥才能生成令牌，用于允许客户登录你的店铺。为避免安全隐患，请确保你的密钥保密。


![image 23.png](https://s2cdn.myshopline.com/slfs/op-new/file/2023/12/22/633808/image23.png)

### 使用 JSON 对客户信息进行编码
客户信息表示为哈希，该哈希必须至少包含客户的电子邮件地址或手机号中的任意一个以及当前时间戳（ ISO8601 编码）。你还可以附上客户的名字、姓氏或多个送货地址。或者，你可以包含客户当前浏览器会话的 IP 地址，使令牌仅适用于来自此 IP 地址的请求。

包含所有必填字段的最小示例可能如下所示：
```json
{
"email": "*********@example.com",
"created_at": "2013-04-11T15:16:23-04:00",
}
```

包含一些可选字段的示例,如下所示：
```json
{
    "email": "*********@example.com",
    "phone": "0086138****1234",
    "created_at": "2013-04-11T15:16:23-04:00",
    "first_name": "S****",
    "last_name": "T*****",
    "tag_string": "canadian, premium",
    "identifier": "bob123",
    "remote_ip": "107.**.***.121",
    "return_to": "http://yourstore.com/some_specific_site",
    "addresses": [{
        "address1": "123 *** St",
        "city": "Ottawa",
        "country": "Canada",
        "first_name": "S****",
        "last_name": "T*****",
        "phone": "+1 123-***-7890",
        "province": "Ontario",
        "zip": "123 ABC",
        "province_code": "ON",
        "country_code": "CA",
        "default": true
    }]
}
```

你可以通过将 "tag_string" 设置为逗号分隔的单字值列表来将标签归因于客户。这些标签将覆盖你可能已经归因于此客户的任何标签。<br/>
如果你希望你的用户看到你的 SHOPLINE 商店的特定页面，你可以使用 return_to 字段。


> **note**
>
> SHOPLINE 的 multipass 登录使用电子邮件地址/手机号码作为商店客户的唯一标识符。在 SHOPLINE 中注册客户时，在以下情况下，商家**必须在**“标识符”字段中设置唯一标识符：
> - 该网站使用其他标识符（如用户名）
> - 网站的两个不同用户可能会使用相同的电子邮件地址注册。如果电子邮件地址始终是唯一的，则不需要设置“标识符”字段。只有一个 SHOPLINE 帐户可以使用特定的电子邮件地址。使用相同的电子邮件地址（即使使用不同的“标识符”）注册第二个客户将导致错误
> - 当同时传入电子邮件地址和手机号码字段时，优先使用电子邮件地址进行登录，并且将手机号码也与该账号进行绑定
> - 手机号码字段遵循**00+区号+手机号**的格式



## 使用 AES 加密 JSON 数据
要生成有效的 multipass 登录令牌，你需要在 SHOPLINE 管理员中为你提供秘钥。该秘钥用于导出两个加密密钥——一个用于加密，一个用于签名。此密钥派生是通过使用 SHA-256 哈希函数完成的（前 128 位用作加密密钥，最后 128 位用作签名密钥）。

加密提供了保密性。它确保没有人能读取客户数据。作为加密密码，我们使用 AES 算法（ 128 位密钥长度、 CBC 操作模式、随机初始化向量）。

## 使用 HMAC 对加密数据进行签名
签名（也称为消息身份验证代码）提供真实性。它确保多通令牌是真实的，并且没有被篡改。我们使用带有 SHA-256 哈希函数的 HMAC 算法，并对第 3 步的加密 JSON 数据（而不是第 2 步的明文 JSON 数据）进行签名。

## Base64 对二进制数据进行编码
Multipass 登录令牌现在由 128 位初始化向量、可变长度密文和 256 位签名（按此顺序）组成。此数据使用 base64 （ URL 安全变体，RFC 4648）进行编码。

## 将你的客户重定向到你的 SHOPLINE 商店
一旦你有了令牌，你应该会触发 HTTP GET 请求到你的 SHOPLINE 商店。

| HTTP GET 请求 |
| :--- |
| api/user/account/login/multipass/insert_token_here |

当请求成功时（例如，令牌有效且未过期），客户将登录你的 SHOPLINE 商店。

Multipass 登录令牌仅在很短的时间内有效，每个令牌只能使用一次。出于这些原因，你不应该提前生成令牌，以便将其渲染到 HTML 站点中。你应该创建一个重定向 URL ，在需要时实时生成令牌，然后自动重定向浏览器。

> **注意**
>
> HTTP 请求的域名可以使用 SHOPLINE 商店的 handle 域名；但如果你的店铺使用自定义域名，请求的域名也需要替换为自定义域名，否则会导致登录失败。


---
## 实施示例
```java
import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;


public static void main(final String[] args) throws Exception {

    final String createAt = ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT);

    final Map<String, String> dataMap = new HashMap<>();

    dataMap.put("email", "peter@shoplineapp.com");

    dataMap.put("created_at", createAt);

    final String dataJson = "..."; //json string from dataMap;

    final String secret = "...";

    final String token = generateToken(secret, dataJson);

    System.out.println(dataJson);
    System.out.println(token);

}

public static String generateToken(final String secret, final String plaintext) throws Exception {

    // SHA-256 hash

    final MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");

    final byte[] encodedHash = messageDigest.digest(secret.getBytes(StandardCharsets.UTF_8));

    final byte[] encryptedKey = new byte[16];

    final byte[] signKey = new byte[16];

    System.arraycopy(encodedHash, 0, encryptedKey, 0, 16);

    System.arraycopy(encodedHash, 16, signKey, 0, 16);

    // iv

    final byte[] iv = new byte[16];

    new SecureRandom().nextBytes(iv);

    final SecretKeySpec encryptedKeySpec = new SecretKeySpec(encryptedKey, "AES");

    final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

    cipher.init(Cipher.ENCRYPT_MODE, encryptedKeySpec, new IvParameterSpec(iv));

    // encrypt byte array

    final byte[] encrypted = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));

    final byte[] ivEncryptedByte = new byte[iv.length + encrypted.length];

    System.arraycopy(iv, 0, ivEncryptedByte, 0, iv.length);

    System.arraycopy(encrypted, 0, ivEncryptedByte, iv.length, encrypted.length);

    final Mac hmac = Mac.getInstance("HmacSHA256");

    final SecretKeySpec signKeySpec = new SecretKeySpec(signKey, "HmacSHA256");

    hmac.init(signKeySpec);

    // sign byte array, 256 bit

    final byte[] signByte = hmac.doFinal(ivEncryptedByte);

    final byte[] tokenBytes = new byte[ivEncryptedByte.length + signByte.length];

    System.arraycopy(ivEncryptedByte, 0, tokenBytes, 0, ivEncryptedByte.length);

    System.arraycopy(signByte, 0, tokenBytes, ivEncryptedByte.length, signByte.length);

    String token = Base64.encodeBase64URLSafeString(tokenBytes);

    token = token.replace('+', '-')

.replace('/', '_');

    return token;

}
```

---


## 安全考虑
SHOPLINE 鼓励你始终在客户数据哈希中设置 remote_ip 字段，以便只有预期的浏览器才能使用令牌。我们还鼓励你使用安全的 HTTPS 连接向浏览器发送令牌。

你应该确保在主网站上注册新帐户需要验证所使用的电子邮件地址。否则，有人可以使用别人的电子邮件地址注册你的主网站，从而在你的 SHOPLINE 商店中访问他的客户帐户。

---

## 常见问题
**我有一个巨大的客户数据库。如何将其与 SHOPLINE 同步，以便我可以使用多通道登录？**<br/>
你不需要同步任何内容。一旦你使用 multipass 重定向客户，我们将自动在你的 SHOPLINE 商店中为他们创建一个客户帐户（如果尚不存在）。

---

**我的一些客户已经下了订单 SHOPLINE 。如何更新这些客户，以便他们可以通过多通行证登录？**<br/>
你可以使用 [客户 API ](https://developer.shopline.com/zh-hans-cn/docs/admin-rest-api/customer/customer-information/customer-number-query.md) 为客户设置**multipass_identifier**。你需要将标识符用于这些客户帐户的所有多通行证请求.

---

**我的秘钥被泄露了。我现在该怎么办？**<br/>
如果你的秘钥泄露，可以在你的商店管理员中禁用它，再重新启用将会生成一个新的秘钥。这将使所有旧 URL 无效。你应该尽快这样做，因为每个知道秘钥的人都可能访问每个客户帐户！

---

**我可以在多个 SHOPLINE 商店之间使用 Multipass 登录吗？**<br/>
不， Multipass 不能用于在多个 SHOPLINE 商店之间登录，而无需重定向到外部网站。

---

**Multipass 登录是否适用于批发渠道？**<br/>
不， Multipass 不能与批发渠道一起使用。

---

**remote_ip 字段是否支持 IPv6 地址？**<br/>
不，仅支持 IPv4 地址。如果 remote_ip 与客户数据哈希中指定的 IP 不匹配， Multipass 返回错误“您无权使用Multipass登录”。
