📜 ⬆️ ⬇️

Local accounts in Microsoft Azure Mobile Services

Another insufficiently described topic about Microsoft Azure Mobile Services is authorization, which is also established only in recent versions. Of course, from the earliest versions there was an enumeration of the MobileServiceAuthenticationProvider, which made it possible to authorize one of the specified methods in a simple way. But this set is hardly the most convenient solution for users. There are two possible directions of expansion - the addition of new versions of the OpenId mechanism or its own authorization mechanism. Next will be considered the second option.

Let's start with the fact that if you use a too old template from Visual Studio to create a project (for example, the 2nd update for 2013), then the NuGet version for WindowsAzure.MobileServices.Backend may not support the solution discussed further. At the time of writing the article with the latest version 1.0.439, there were difficulties of compatibility with new versions of other modules, so the following set is used here:
Install-Package AutoMapper -Version 3.2.1 Install-Package System.IdentityModel.Tokens.Jwt -Version 3.0.2 Install-Package Microsoft.Owin.Security -Version 2.1.0 Install-Package Microsoft.Owin.Security.OAuth -Version 2.1.0 Install-Package Microsoft.Owin.Security.Cookies -Version 2.1.0 Install-Package Microsoft.Owin.Security.Jwt -Version 2.1.0 Install-Package Microsoft.Owin.Security.ActiveDirectory -Version 2.1.0 Install-Package Microsoft.Owin.Security.Facebook -Version 2.1.0 Install-Package Microsoft.Owin.Security.Google -Version 2.1.0 Install-Package Microsoft.Owin.Security.Twitter -Version 2.1.0 Install-Package Microsoft.Owin.Security.MicrosoftAccount -Version 2.1.0 Install-Package WindowsAzure.MobileServices.Backend.Entity -Version 1.0.405 

First, create the classes DemoCredentials (inherited from ProviderCredentials) and LocalLoginProvider (inherited from LoginProvider) and declare them as follows:
  public class DemoCredentials: ProviderCredentials { public string AccessToken { get; set; } public DemoCredentials() : base(DemoLoginProvider.ProviderName) { } } public class DemoLoginProvider: LoginProvider { public const string ProviderName = "Demo"; public override string Name { get { return ProviderName; } } public DemoLoginProvider(IServiceTokenHandler tokenHandler) : base(tokenHandler) { } public override void ConfigureMiddleware(Owin.IAppBuilder appBuilder, Microsoft.WindowsAzure.Mobile.Service.ServiceSettingsDictionary settings) { return; } public override ProviderCredentials CreateCredentials(System.Security.Claims.ClaimsIdentity claimsIdentity) { System.Security.Claims.Claim name = claimsIdentity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier); System.Security.Claims.Claim providerAccessToken = claimsIdentity.FindFirst(ServiceClaimTypes.ProviderAccessToken); DemoCredentials credentials = new DemoCredentials { UserId = this.TokenHandler.CreateUserId(Name, name != null ? name.Value : null), AccessToken = providerAccessToken != null ? providerAccessToken.Value : null }; return credentials; } public override ProviderCredentials ParseCredentials(Newtonsoft.Json.Linq.JObject serialized) { return serialized.ToObject<DemoCredentials>(); } } 

The ConfigureMiddleware method is not needed in this case, since it is intended for external authorization.

Next, create an API controller and declare the main authorization method in it, which will return the data type LoginResult. To simplify the example, there will be no verification of authorization parameters in it, I suppose readers will have no difficulty adding the method of checking them necessary for a specific task.
  [HttpPost] [Route("api/Authentication/Authenticate")] [AllowAnonymous] public async Task<HttpResponseMessage> Authenticate() { DemoLoginProvider provider = new DemoLoginProvider(Handler); System.Security.Claims.ClaimsIdentity claimsIdentity = new System.Security.Claims.ClaimsIdentity(); claimsIdentity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.NameIdentifier, "fakeUser")); LoginResult loginResult = provider.CreateLoginResult(claimsIdentity, Services.Settings.MasterKey); return Request.CreateResponse(HttpStatusCode.OK, loginResult); } 

The LoginResult class contains a very important parameter - AuthenticationToken, which will be needed on the client side. It is issued by the server for the time specified in the parameters and determines the very fact of authorization on behalf of a specific user - in this case, “Demo: fakeUser”.

The Handler property is declared in the controller as follows:
  public IServiceTokenHandler Handler { get; set; } 

After that, Autofac will set its desired value.
')
Next, we consider an example of a client application based on Xamarin.Android. You can use the same build, but for purposes of demonstrating cross-platform capabilities, PCL with a profile 111 will be used. This profile is supported in Xamarin.Android, Xamarin.iOS and WinStore-applications. To simplify the example, an abbreviated number of application layers will be used, and the implementation of the user interface will eliminate the activity life cycle processing. Run the command:
 Install-Package WindowsAzure.MobileServices 

Then we implement the authorization method:
  public async Task AuthenticateAsync() { LoginResultDTO loginResult = await _channel.InvokeApiAsync<LoginResultDTO>("Authentication/Authenticate").ConfigureAwait(false); MobileServiceUser user = new MobileServiceUser(loginResult.User.UserId) { MobileServiceAuthenticationToken = loginResult.AuthenticationToken }; _channel.CurrentUser = user; } 


After that, when calling any controller method that requires authorization, the User property of the controller will contain the specified value “Demo: fakeUser”. The remaining parts of the client application contain lines of code that are common in other applications. For a more detailed study, the sample source archive can be downloaded here .

Source: https://habr.com/ru/post/247199/


All Articles