メイン コンテンツにスキップ

 Subscribe

We just released a new set of features for Azure Mobile Services .NET including:

  • Support for CORS using ASP.NET Web API CORS enabling first class support for specifying CORS policy at a per-service, per-controller, or per-action level.
  • An extensible authentication model enabling you to control which authentication mechanisms are available for your mobile service clients. For example, you can add your own authentication mechanisms in addition to or in place of the default support for Azure Active Directory, Twitter, Facebook, Google, and Microsoft Account.
  • Support for Azure Active Directory Authentication using a server-side flow simplifying client authentication significantly.

 

If you are new to Azure Mobile Services .NET then check out this great overview and here is more information about Azure Mobile Services in general.

You can always let us know what you think via our MSDN forum or you can tweet me @frystyk.

Getting the Updates

Regardless of whether you start from a Mobile Service QuickStart or from a Visual Studio Project, you can you can get the updates (version 1.0.342) from NuGet. Simply go to the NuGet Package Manager in your Visual Studio project, select Updates, and type windowszure.mobileservices in the search window. It should look similar to this:

Updating to Azure Mobile Services version 1.0.342

Install the Mobile Services updates by searching for windowsazure.mobileservices and you are ready to go. These packages will include whatever other updates they need so don’t update other packages manually.

CORS Support

First up is built-in support for CORS leveraging the support provided by the ASP.NET Web API CORS nuget package. For a great introduction to CORS in ASP.NET Web API including how to use the EnableCorsAttribute to control the settings, please see the blog CORS Support in ASP.NET Web API 2.

By default, Azure Mobile Services enables CORS with a default policy that doesn’t allow any CORS requests. If you just want to set the list of allowed origin domains then you can do that via the portal or through config using the MS_CrossDomainOrigins app setting with a value of comma-separated origins, for example:

This will enable access from the two origins https://testhost and https://sample using any HTTP method and any HTTP headers.

It is possible to set an entirely different default policy by modifying the ConfigOptions instance used to configure your service. Simply set the policy doing something like this:

public static class WebApiConfig
{
    public static void Register()
    {
        // Use this class to set configuration options for your mobile service
        ConfigOptions options = new ConfigOptions();
        options.CorsPolicy =
            new System.Web.Http.Cors.EnableCorsAttribute("*", "*", "*");
        ...
    }
}

As always, you can of course also set a particular CORS policy on a per-controller and/or a per-action basis allowing for great flexibility in how you want to use CORS.

Extensible Authentication Model

Azure Mobile Services provides a common authentication model across Azure Active Directory, Twitter, Facebook, Google, and Microsoft Account. But in addition to these login providers, you can now add your own or even modify or remove the default ones.

For example, you can add support for Custom Authentication as described in the documentation Get started with custom authentication. You can also leverage other OWIN authentication providers to add support for additional identity providers. Creating a LoginProvider requires four steps exemplified below by showing how to add support for LinkedIn using the Owin.Security.Providers NuGet package:

First, you create an implementation of a  LoginProvider targeting the LinkedIn middleware which performs three tasks:

  • Register the LinkedIn OWIN middleware so that it can participate in the authentication
  • Serialize the access token obtained from LinkedIn
  • Deserialize the access token again

The code should look similar to this:

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();
    }
}

Note that we leverage two new custom application settings (LinkedInClientId and LinkedInClientSecret) which can be set directly in the local Web.config file to set the LinkedIn client ID and secret through configuration – more about this later.

Second step is to ensure that the LinkedIn access token is added as a claim to our identity:

public class LinkedInLoginAuthenticationProvider : LinkedInAuthenticationProvider
{
    public override Task Authenticated(LinkedInAuthenticatedContext context)
    {
        context.Identity.AddClaim(
            new Claim(ServiceClaimTypes.ProviderAccessToken, context.AccessToken));
        return base.Authenticated(context);
    }
}

Third step is to define a ProviderCredentials class which includes the access token as a public property:

public class LinkedInCredentials : ProviderCredentials
{
    public LinkedInCredentials()
        : base(LinkedInLoginProvider.ProviderName)
    {
    }

    public string AccessToken { get; set; }
}

The forth and final step is to register our new LoginProvider with our service. We do this in the Register method in the WebApiConfig class:

public static class WebApiConfig
{
    public static void Register()
    {
        ConfigOptions options = new ConfigOptions();
        options.LoginProviders.Add(typeof(LinkedInLoginProvider));

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

Add the app settings for the client ID and client secret to the local web.config file:


You can now run your service locally in Visual Studio and point your browser at the address /login/linkedin which after a redirect should provide a page looking similar to this:

Using the LinkedIn LoginProvider on service running locally.

Logging in using your LinkedIn credentials will then get you redirected to a final URI looking something like this: https://localhost:31475/login/done#token=. To use your new LoginProvider from the client, you simply use the string “LinkedIn” to point to it:

private async Task AuthenticateAsync()
{
    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();
    }
}

Azure Active Directory Authentication

Azure Mobile Services .NET already supports authentication using Active Directory Authentication Library Single Sign-On but has not until now supported the server flow required for client platforms that aren’t currently supported by Active Directory Authentication Library.

The default Azure Active Directory LoginProvider supports the client side flow provided by Active Directory Authentication Library but this only works on client platforms where that library is supported.

To enable the server-side flow, which can work with any client supported by Azure Mobile Services, first install the Microsoft Azure Mobile Services .NET Backend Security Extension Nuget preview package into your server project. Then replace the default Azure Active Directory LoginProvider by doing the following in your Register method in the WebApiConfig class:

public static class WebApiConfig
{
    public static void Register()
    {
        ConfigOptions options = new ConfigOptions();
        options.LoginProviders.Remove(typeof(AzureActiveDirectoryLoginProvider));
        options.LoginProviders.Add(typeof(AzureActiveDirectoryExtendedLoginProvider));

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

The AzureActiveDirectoryExtendedLoginProvider class supports both the client and server flow allowing you to use whatever works best for your respective client platforms.

To find out more about the general Mobile Services authentication model, please see the documentation topic Get started with authentication in Mobile Services.

That’s it! I hope these features are helpful – if there are others that you would like to see then please let us know!

Have fun!

Henrik

  • Explore

     

    Let us know what you think of Azure and what you would like to see in the future.

     

    Provide feedback

  • Build your cloud computing and Azure skills with free courses by Microsoft Learn.

     

    Explore Azure learning


Join the conversation