Microsoft Azure Mobile Service添加第三方用户认证服务(LinkedIn为例)

  Azure官方支持Microsoft、Google、Twitter、Facebook、Windows Azure Active Directory五种账户登录。但是很多情况下,开发者希望配置其他账户登录功能,比如LinkedIn、微信、微博等等。这篇博客将介绍如何通过加载扩展身份认证SDK,实现LinkedIn登录功能。

第一步,新建Azure Mobile Service,后端采用.Net实现(因为只有.Net支持添加新的第三方账户认证)。

第二步,在Portal下载的Mobile Service工程中,在后端Service工程中添加Owin.Security.Providers包。

 

第三步,在后端工程中创建LoginProvider,以实现LinkedIn为例。

1. 创建一个基于LoginProvider的实现,包括三点:

 1) 注册LinkedIn OWIN中间件以配置身份认证内容;

 2) 将从LinkedIn获得的登录token序列化;

 3) 解析获得的登录token,获取内部信息;

 具体实现:为了便于分类,可以在后端工程中创建一个新的文件夹,起名LinkedInLogin,在其中添加一个类文件LinkedInLoginProvider.cs

using System.Linq;

using System.Threading.Tasks;

using System.Web.Http;

using System.Web.Http.Controllers;

using System.Web.Http.OData;

using Microsoft.WindowsAzure.Mobile.Service;

using Owin.Security.Providers;

using Microsoft.WindowsAzure.Mobile.Service.Security;

using Owin;

using System.Security.Claims;

using Newtonsoft.Json.Linq;

using Owin.Security.Providers.LinkedIn;

using LiusjMobileforLinkedinService.LinkedInLogin; //<后段工程名>.<新建文件夹名>,即引用该文件夹

 

namespace LiusjMobileforLinkedinService

{

    public class LinkedInLoginProvider : LoginProvider

    {

        internal const string ProviderName = "LinkedIn";

 

        public LinkedInLoginProvider(IServiceTokenHandler tokenHandler)

            : base(tokenHandler)

        {

        }

 

        public override string Name

        {

            get { return ProviderName; }

        }

 

        public override void ConfigureMiddleware(IAppBuilder appBuilder,

            ServiceSettingsDictionary settings)

        {

            LinkedInAuthenticationOptions options = new LinkedInAuthenticationOptions

            {

                ClientId = settings["LinkedInClientId"],

                ClientSecret = settings["LinkedInClientSecret"],

                AuthenticationType = this.Name,

                Provider = new LinkedInLoginAuthenticationProvider()

            };

            appBuilder.UseLinkedInAuthentication(options);

        }

 

        public override ProviderCredentials CreateCredentials(

            ClaimsIdentity claimsIdentity)

        {

            Claim name = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier);

            Claim providerAccessToken = claimsIdentity

                .FindFirst(ServiceClaimTypes.ProviderAccessToken);

 

            LinkedInCredentials credentials = new LinkedInCredentials

            {

                UserId = this.TokenHandler.CreateUserId(this.Name, name != null ?

                    name.Value : null),

                AccessToken = providerAccessToken != null ?

                    providerAccessToken.Value : null

            };

 

            return credentials;

        }

 

        public override ProviderCredentials ParseCredentials(JObject serialized)

        {

            return serialized.ToObject<LinkedInCredentials>();

        }

    }

}

 

2. 要求获取LinkedIn登录token

 具体实现:创建一个新的类文件LinkedInLoginAuthenticationProvider.cs

using System.Linq;

using System.Threading.Tasks;

using System.Web.Http;

using System.Web.Http.Controllers;

using System.Web.Http.OData;

using Microsoft.WindowsAzure.Mobile.Service;

using Owin.Security.Providers;

using Microsoft.WindowsAzure.Mobile.Service.Security;

using Owin;

using System.Security.Claims;

using Newtonsoft.Json.Linq;

using Owin.Security.Providers.LinkedIn;

 

namespace LiusjMobileforLinkedinService

{

    public class LinkedInLoginAuthenticationProvider : LinkedInAuthenticationProvider

    {

        public override Task Authenticated(LinkedInAuthenticatedContext context)

        {

            context.Identity.AddClaim(

                new Claim(ServiceClaimTypes.ProviderAccessToken, context.AccessToken));

            return base.Authenticated(context);

        }

    }

}

 

3. 定义一个ProviderCredentials类,将登录token作为一个公共属性

 具体实现:创建一个新的类文件LinkedInCredentials.cs

using Owin.Security.Providers;

using Microsoft.WindowsAzure.Mobile.Service.Security;

using Owin;

using System.Security.Claims;

using Newtonsoft.Json.Linq;

using Owin.Security.Providers.LinkedIn;

 

namespace LiusjMobileforLinkedinService.LinkedInLogin

{

    public class LinkedInCredentials : ProviderCredentials

    {

        public LinkedInCredentials()

            : base(LinkedInLoginProvider.ProviderName)

        {

        }

 

        public string AccessToken { get; set; }

    }

}

 

  在完成前三步后,LinedInLogin中实现了上述的三个文件,实际上LinkedInLoginAuthenticationProvider和LinkedInCredentials都是为LinkedInLoginProvider这个对象服务的。

 

4. 在后台中注册新实现的LoginProvider,具体来说通过WebApiConfig类中的Register方法实现

public static void Register()

        {

            ConfigOptions options = new ConfigOptions();

            options.LoginProviders.Add(typeof(LinkedInLoginProvider));

 

            HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options));

           

            Database.SetInitializer(new LiusjMobileforLinkedinInitializer());

            config.SetIsHosted(true);

        }

 

5. 在web.config文件中添加ClientID和ClientSecret的设置

<add key="LinkedInClientId" value="your value here" />

<add key="LinkedInClientSecret" value="your value here" />

 

注:获取客户端ID和密钥的具体方法

 1) 通过网址https://developer.linkedin.com/,登录LinkedIn开发者网站;

 2) 要想通过LinkedIn登录,需要首先注册新应用。点击页面上方Support --> API keys --> Add New Application

 3) 在出现的注册应用的表格中,特别注意在OAuth User Agreement一栏:

  a. 通过勾选Default Scope来确认返回Token中包含的信息;

  b. 在OAuth2.0 Redirect URLs中填写指向Azure Mobile Service后台服务的登录URL:

https://<Mobile Service后台服务地址>/signin-linkedin

 4) 确认后,可以获得该应用的密钥信息,其中API key就是ClientID,Secret Key就是ClientSecret。

 

第四步,将该后台服务发布到Azure Mobile Service上,此时可以在浏览器中通过访问REST API去检查登录配置是否成功:REST API为https://liusjmobileforlinkedin.azure-mobile.net/login/linkedin,登录后就可以访问后台服务了

第五步,如果希望在客户端使用LoginProvider,只需要通过字符串”linkedin”标示。

  具体实现:在MainPage.cs中添加登录函数AuthenticateAsync,并在首页导航函数中调用它。

protected override async void OnNavigatedTo(NavigationEventArgs e)

        {

            await AuthenticateAsync();

            await RefreshTodoItems();

        }

        private async Task AuthenticateAsync()

        {

            Microsoft.WindowsAzure.MobileServices.MobileServiceUser user = null;

            while (user == null)

            {

                string message;

                try

                {

                    user = await App.MobileService.LoginAsync("linkedin");

                    message = string.Format("You are now logged in - {0}", user.UserId);

                }

                catch (InvalidOperationException)

                {

                    message = "You must log in. Login Required";

                }

 

                var dialog = new MessageDialog(message);

                dialog.Commands.Add(new UICommand("OK"));

                await dialog.ShowAsync();

            }

        }

 

  这时就可以在客户端实现LinkedIn登录,登陆后程度设置显示LinkedIn的用户ID

 

最后说几个特别需要注意的事

 1.  当采用LinkedIn身份认证时,一定不要在Azure Portal的身份认证一栏配置其他账户认证(比如Microsoft Live ID),否则就无法成功了。

 2.  在开启客户端时,别忘了将App.xaml.cs中的Mobile Service连接URL和密钥加上哦。

public static MobileServiceClient MobileService = new MobileServiceClient( "<Mobile Service URL>", "<Mobile Service密钥>" );