文章 使用第三方服务登录

OAuth 为用户提供了一种使用支持 OAuth 标准的其他流行网站(如Facebook或Twitter)的凭据登录到 Limyee 电商平台的方法。

开发人员可以为支持 OAuth 的其他站点添加其他登录选项。Limyee 电商平台的提供程式仅从用户那里收集登录网站所需的信息。

开始

实现 IOAuthClient 就可以使用第三方服务来提供用户身份验证的功能。我们的示例实现将基于"支付宝 OAuth"流程。使用此示例需要你在支付宝的开放平台创建一个"网页&移动应用",以便获取客户端密钥及相关开发信息。您可以在此处找到更多详细信息并设置客户端应用程序:获取会员信息产品介绍 - 支付宝文档中心 (alipay.com)

必需的 DLLs:

  • Limyee.Common
  • Limyee.Components
  • Limyee.Api
  • Limyee.OAuth

现有客户
Limyee 电商平台已经有许多 OAuth 客户端,只需启用和配置相应的插件即可管理这些客户端。这些都是 IOAuthClient 接口的实现。如果您不使用这些服务而需使用其他服务时,则需要开发自定义客户端。请注意,您计划实现 IOAuthClient 的接口服务必须支持 OAuth 标准。

  • QQ
  • 微信公众号平台
  • 微信开放平台
  • 微博
  • 支付宝
  • 支付宝小程序
  • Facebook
  • Google
  • LinkedIn
  • Live Connect
  • Salesforce
  • Twitter

定义客户端属性

我们将接口中的多个属性定义为常量值,供以后使用。

客户端名称是 Limyee 电商平台在引用客户端时使用的名称,当鼠标悬停在图标上显示的文本。

public string ClientName { get { return "Alipay"; } }

客户端类型必须是所有 OAuth 客户端中的唯一值,用于标识您的客户端。

public string ClientType { get { return "alipay"; } }

主题颜色是基于十六进制的颜色值,它为客户端提供用于显示目的的其他标识。虽然此属性未在当前默认平台主题中使用,但可由自定义主题使用。

public string ThemeColor { get { return "00AAEE"; } }

当您使用外部服务创建应用程序时,应为您生成 ConsumerKey 和 ConsumerSecret。这里建议使用IConfigurablePlugin,以便可以通过Limyee电商平台站点中的管理来编辑值。

public virtual string ConsumerKey { get { return Configuration.GetString("ConsumerKey"); } }
public virtual string ConsumerSecret { get { return Configuration.GetString("ConsumerSecret"); } }

隐私声明是一个简单的文本字段,允许您向用户提供有关使用此登录方法的法律信息。

// Your privacy statement should include what privacy information
//  is being collected about the user using this OAuth client.
public string Privacy
{
    get { return "Privacy statement"; }
}

Enabled 和 CallbackUrl 都由 Limyee 电商平台管理。Enabled 可以硬编码为 true,而 CallbackUrl 可以验证或解码回调地址,这里将 CallbackUrl 编码为 Base64。

public bool Enabled { get { return true; } }

private string Base64CallbackUrl { get; set; }
public virtual string CallbackUrl
{
    get { return Encoding.UTF8.GetString(Convert.FromBase64String(Base64CallbackUrl)); }
    set { Base64CallbackUrl = Convert.ToBase64String(Encoding.UTF8.GetBytes(value)); }
}

ClientLogoutScript 允许在 Limyee 电商平台中注销时执行一些其他操作。这是 Javascript,当客户端在通过此 OAuth 客户端登录后注销时,将执行该脚本。如果需要,可以使用它来执行进一步的操作。支付宝的实现不需要使用它,因此我们将其留空。

public string ClientLogoutScript
{
    get { return ""; }
}

IconUrl 用于在将 OAuth 客户端显示为登录选项的图像。它将 URL 返回到表示 OAuth 提供程序的图像。您可以链接到外部 URL 或将图像添加到集中文件存储并链接到该 URL。

public string IconUrl 
{ 
    get 
    { 
        try
        {
            var file = CentralizedFilesStorage.GetFileStore("oauthimages").GetFile(string.Empty, "alipay.png");
            
            if (file != null)
                return file.GetDownloadUrl();
            else
                return null;
        }
        catch
        {
            return null;
        }
    } 
}

GetAuthorizationLink 方法仅提供用于最初请求外部站点访问令牌的 URL。查询字符串属性和其他格式设置将由第三方服务指定,这里,按指定设置 scope 的值为 auth_user。

protected string RedirectUri
{
    get { return Globals.FullPath(SiteUrls.Instance().OAuthSignin(ClientType)); }
}

public string GetAuthorizationLink()
{
    return string.Format("{0}/?app_id={1}&redirect_uri={2}&state={3}&scope=auth_user", 
        "https://openauth.alipay.com/oauth2/publicAppAuthorize.html", 
        ConsumerKey, 
        RedirectUri,
        Globals.UrlEncode(CallbackUrl));
}

处理登录

客户端的主要工作是根据来自外部服务的响应中的信息处理用户的登录。首先,我们执行一些健全性检查。查询字符串中是否存在错误可能取决于第三方服务的实现。

using Limyee.OAuth.Version2;
using Limyee.Common;

private readonly IOAuth OAuthV2Service = Services.Get<IOAuth>();

public OAuthData ProcessLogin(HttpContextBase context)
{
    if (!Enabled || context.request.QueryString["error"] != null || context.Request.QueryString["auth_code"] == null)
        OAuthV2Service.FailedLogin();

接下来,我们需要重置 CallbackUrl 以处理 OAuthHandler。

    if (context.Request.QueryString["state"] == null)
        FailedLogin();
        
    Base64CallbackUrl = context.Request.QueryString["state"];

获取访问令牌

一旦身份验证代码到位,我们就可以使用它来获取访问令牌。 访问令牌本身将使我们能够安全地访问支付宝资源。在 ProcessLogin方法中,我们调用一个私有方法来获取访问令牌:

string token = GetAccessToken(authorizationCode);

如果我们进一步检查此方法,您可以看到我们正在使用获取的身份验证代码向支付宝发出另一个 HTTP 请求,以获取访问令牌。首先,我们使用所需的参数、数据和请求属性设置请求。(其他服务可能因数据处理而异)。 然后,我们将读取响应以提取访问令牌,我们将使用这些令牌来获取有关您的支付宝的帐户信息。 

private string getAccessToken(string auth_code)
{
    var request = new AlipaySystemOauthTokenRequest
    {
        GrantType = "authorization_code",
        Code = auth_code
    };
    AlipaySystemOauthTokenResponse response = null;
    try
    {
        // get ALIPAYCLIENT from alipay sdk
        response = ALIPAYCLIENT.Execute(request, null, null);
    
    }
    catch (Exception e)
    {
        throw new Exception(e.Message);
    }
    
    if (response.IsError)
        throw new Exception(response.SubMsg);
        
    return response.AccessToken;
}

获取用户的数据

现在,我们终于拥有了使用我们之前请求的访问令牌代表用户调用支付宝 API 的完全授权。虽然 OAuth 流程告诉我们用户存在于支付宝中,并且已经通过它们成功进行了身份验证,但它没有为 Limyee 电商平台提供足够的信息来建立帐户。 为此,我们必须从支付宝获取有关用户的更多信息,这些信息至少足以提供建立唯一的用户名。 如果服务支持提供电子邮件地址,也可以获取电子邮件地址,尽管这不是必需的。 如果电子邮件地址不可用,Limyee 电商平台将提示用户输入一个电子邮件地址。 Limyee 电商平台中的电子邮件地址和用户名必须是唯一的。您可以看到,我们还在此过程中提取用户数据 (Limyee.Extensibility.Authentication.Version1.OAuthData),我们在 ProcessLogin 返回时调用它。

return GetUserData(token);

以下是返回的 OAuthData 类。

public class OAuthData
{
    public string ClientId { get; set; }
    public string ClientType { get; set; }
    public string UserName { get; set; }
    public string Email { get; set; }
    public string CommonName { get; set; }
    public string AvatarUrl { get; set; }
    public string CallingIso { get; set; }
    public string CallingNumber { get; set; }
}

至少在 OAuthData 对象上设置以下信息:

  • ClientId - 大多数服务都有一个 ID 或某个值来唯一标识该系统中的用户。此处应使用该值。对于每个客户端类型,它应该是唯一的。与 ClientType 一起,将用于标识使用此客户端进行身份验证用户。
  • ClientType - 这标识 OAuth 客户端本身,只需将其设置为使用它的 IOAuthClient 实现的 ClientType 属性即可。
  • UserName - 这是将分配给平台用户的用户名,并且必须是唯一的。

还有一个 Email 属性,如果服务有提供的,则应设置该属性。否则,Limyee 电商平台将在用户第一次使用客户端登录时,要求用户提供电子邮件地址。

我们还在 OAuthData 上填充了一个名为 CommonName 的可选参数。如果您在此处提供一个值,它将设置用户的 DisplayName,这是一种更友好的方法来标识用户,而不是显示用户名。它不必是唯一的。

查看结果

编译插件并将其添加到Limyee电商平台后,您可以启用它,输入APPID和密钥,您的用户将能够使用支付宝登录。登录页面上将有一个图标,点击将开始登录过程。