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密钥>" );