首页 文章

在Windows Azure移动服务中实施自定义身份验证

提问于
浏览
6

Windows Azure移动服务目前没有自定义身份验证选项并查看功能请求

http://feedback.azure.com/forums/216254-mobile-services/suggestions/3313778-custom-user-auth

它不会很快到来 .

使用.NET后端和.NET应用程序,如何实现自定义身份验证,以便您不必使用Facebook,Google或其他任何当前提供商?

关于如何使用JS后端以及iOS和Android完成这一步,有很多部分完成的教程,但.NET示例在哪里?

2 回答

  • 1

    我终于完成了解决方案,在下面列出的文章的帮助下,一些intellisense和一些试验和错误 .

    How WAMS Works

    首先,我想以一种非常简单的形式描述WAMS是什么,因为这部分让我困惑了一段时间,直到它最终点击 . WAMS只是为了快速部署而打包的预先存在的技术的集合 . 您需要了解的情况是:

    enter image description here

    正如您所看到的,WAMS实际上只是WebAPI和其他东西的容器,我在此不再赘述 . 在Azure中创建新的移动服务时,您可以下载包含WebAPI的项目 . 他们使用的示例是TodoItem,因此您将通过项目看到此场景的代码 .

    下面是你从这里下载这个例子的地方(我刚刚做了一个Windows Phone 8应用程序)

    enter image description here

    我可以继续讨论这个问题,但本教程将帮助您入门:

    http://azure.microsoft.com/en-us/documentation/articles/mobile-services-dotnet-backend-windows-store-dotnet-get-started/

    Setup WAMS Project

    您将需要MasterKey和ApplicationKey . 您可以从Azure门户获取它们,单击您的移动服务应用程序并按下底部的管理密钥

    enter image description here

    您刚下载的项目,在Controllers文件夹中我刚刚创建了一个名为AccountController.cs的新控制器,我在里面放了

    public HttpResponseMessage GetLogin(String username, String password)
        {
            String masterKey = "[enter your master key here]";
            bool isValidated = true;
    
            if (isValidated)
                return new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("{ 'UserId' : 'F907F58C-09FE-4F25-A26B-3248CD30F835', 'token' : '" + GetSecurityToken(new TimeSpan(1,0, 0), String.Empty, "F907F58C-09FE-4F25-A26B-3248CD30F835", masterKey)  + "' }") };
            else
                return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Username and password are incorrect");
    
        }
    
        private static string GetSecurityToken(TimeSpan periodBeforeExpires, string aud, string userId, string masterKey)
        {
            var now = DateTime.UtcNow;
            var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            var payload = new
            {
                exp = (int)now.Add(periodBeforeExpires).Subtract(utc0).TotalSeconds,
                iss = "urn:microsoft:windows-azure:zumo",
                ver = 2,
                aud = "urn:microsoft:windows-azure:zumo",
                uid = userId
            };
    
            var keyBytes = Encoding.UTF8.GetBytes(masterKey + "JWTSig");
            var segments = new List<string>();
    
            //kid changed to a string
            var header = new { alg = "HS256", typ = "JWT", kid = "0" };
            byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
            byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
            segments.Add(Base64UrlEncode(headerBytes));
            segments.Add(Base64UrlEncode(payloadBytes));
            var stringToSign = string.Join(".", segments.ToArray());
            var bytesToSign = Encoding.UTF8.GetBytes(stringToSign);
            SHA256Managed hash = new SHA256Managed();
            byte[] signingBytes = hash.ComputeHash(keyBytes);
            var sha = new HMACSHA256(signingBytes);
            byte[] signature = sha.ComputeHash(bytesToSign);
            segments.Add(Base64UrlEncode(signature));
            return string.Join(".", segments.ToArray());
        }
    
        // from JWT spec
        private static string Base64UrlEncode(byte[] input)
        {
            var output = Convert.ToBase64String(input);
            output = output.Split('=')[0]; // Remove any trailing '='s
            output = output.Replace('+', '-'); // 62nd char of encoding
            output = output.Replace('/', '_'); // 63rd char of encoding
            return output;
        }
    

    您可以使用自己的验证代码替换GetLogin中的内容 . 验证后,它将返回所需的安全令牌(JWT) .

    如果您正在测试localhost,请记住进入web.config文件并填写以下密钥

    <add key="MS_MasterKey" value="Overridden by portal settings" />
    <add key="MS_ApplicationKey" value="Overridden by portal settings" />
    

    您需要在此处输入主密钥和应用程序密钥 . 当您上传它们时它们将被覆盖,但如果您在本地运行所有内容,则需要输入它们 .

    在TodoItemController的顶部添加AuthorizeLevel属性,如下所示

    [AuthorizeLevel(AuthorizationLevel.User)]
    public class TodoItemController : TableController<TodoItem>
    

    您需要修改TodoItemController中的大多数函数,但这里是Get All函数的一个示例 .

    public IQueryable<TodoItem> GetAllTodoItems()
        {
            var currentUser = User as ServiceUser;
    
            Guid id = new Guid(currentUser.Id);
    
            return Query().Where(todo => todo.UserId == id);
        }
    

    只是旁注我使用UserId作为Guid(uniqueidentifier),你需要将它添加到todo模型定义中 . 您可以将UserId设置为您想要的任何类型,例如INT32

    Windows Phone/Store App

    Please note that this is just an example and you should clean the code up in your main application once you have it working.

    在您的客户端应用程序

    安装NuGet包:Windows Azure移动服务

    进入App.xaml.cs并将其添加到顶部

    public static MobileServiceClient MobileService = new MobileServiceClient(
              "http://localhost:50527/",
              "[enter application key here]"
        );
    

    在我创建的MainPage.xaml.cs中

    public class Token
    {
        public Guid UserId { get; set; }
        public String token { get; set; }
    }
    

    在主类中添加一个Authenticate函数

    private bool Authenticate(String username, String password)
        {
            HttpClient client = new HttpClient();
            // Enter your own localhost settings here
            client.BaseAddress = new Uri("http://localhost:50527/");
    
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
            HttpResponseMessage response = client.GetAsync(String.Format("api/Account/Login?username={0}&password={1}", username, password)).Result;
    
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var token = Newtonsoft.Json.JsonConvert.DeserializeObject<Token>(response.Content.ReadAsStringAsync().Result);
    
                App.MobileService.CurrentUser = new MobileServiceUser(token.UserId.ToString());
                App.MobileService.CurrentUser.MobileServiceAuthenticationToken = token.token;
    
                return true;
            }
            else
            {
                //Something has gone wrong, handle it here
                return false;
            }           
    
        }
    

    然后在Main_Loaded函数中

    private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            Authenticate("test", "test");
    
            RefreshTodoItems();
        }
    

    如果您在WebAPI中有断点,您将看到它进入,获取令牌,然后返回ToDoItemController,currentUser将填充UserId和令牌 .

    您将需要创建自己的登录页面,与此方法一样,您不能将自动创建的登录页面与其他身份提供程序一起使用 . 但是我更喜欢创建自己的登录屏幕 .

    任何其他问题在评论中告诉我,如果可以,我会帮助 .

    Security Note

    请记住使用SSL .

    References

    [] http://www.thejoyofcode.com/Exploring_custom_identity_in_Mobile_Services_Day_12_.aspx

    [] http://www.contentmaster.com/azure/creating-a-jwt-token-to-access-windows-azure-mobile-services/

    [] http://chrisrisner.com/Custom-Authentication-with-Azure-Mobile-Services-and-LensRocket

  • 20

    这正是你如何做到的 . 这个男人需要10颗星和5箱啤酒!

    有一点,我使用移动服务LoginResult进行登录,如:var token = Newtonsoft.Json.JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync() . Result);

    希望现在进入Android!

相关问题