2017年3月23日

[Azure IoT Suite]使用客製化的登入驗證登入IoT Suite網站

Azure IoT Suite提供了一個Pre-Configured的解決方案,讓開發人員可以快速的開發IoT方案而無須全部從頭開始。由於是"Pre-Configured",因此這個方案有許多的前提假設,其中一個假設是,人員需要透過Azure AD來管控。而某些情況下,特別是當我們需要將現有人員資料的方案與IoT Suite整合時,這常常會造成一些額外的挑戰。

Azure IoT Suite基本上是一個ASP.Net MVC的專案,透過OWIN來做身分驗證,因此,如果我們想要將現有的人員管控機制(例如資料庫)IoT Suite整合時,我們還是可以透過OWIN來提供另外一種身分驗證機制。

l   首先,下載最新版本的IoT Suite Source Code

l   打開NUGet Manager,安裝Microsoft.AspNet.Identity.Core套件。

l   修改APP_Start\Startup.Auth.cs;刪除或Markapp.UseOpenIdConnectAuthentication呼叫修改UseCookieAuthentication呼叫如下:

app.UseCookieAuthentication(new CookieAuthenticationOptions()

            {

                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,

                LoginPath = new PathString("/Account/Signin")

            });

你的Startu.Auth.cs看起來會像這樣子

l   接著,我們需要實作我們自己的身分驗證機制(例如透過資料庫驗證使用者帳號密碼是否正確,並取得使用者的腳色等等)。為了簡單明瞭起見,在這裡我並不真正的連接到資料庫,而是先將使用者資料寫死在程式裡。一旦熟悉了程式寫法,你可以自行修改為符合實際需求。

l   建立一個新的檔案名為User.cs,加入以下程式碼;這個User類別即是我們用以代表使用者資料的Model

using Microsoft.AspNet.Identity;

 

namespace MyAuth.Models

{

    public class User : IUser<string>

    {

        public string Id { get; set; }

        public string UserName { get; set; }

        public string FirstName { get; set; }

    }

}

l   接著,建立一個UserRoleStore.cs檔案,加入代碼如下。同樣的,為了簡化並使容易了解,我並沒有全部實作所有的介面方法。實際使用時,你也許會需要實作相關的CRUD操作。

程式碼中highlight的部分,即是我有修改的部分,為了簡單,我在這裡寫死了使用者資料以及所屬的腳色群組(Admin)

using System;

using System.Collections.Generic;

using System.Threading.Tasks;

using Microsoft.AspNet.Identity;

using MyAuth.Models;

 

namespace MyAuth.Security

{

    public class UserRoleStore : IUserStore< MyAuth.Models.User>,

IUserRoleStore< MyAuth.Models.User>

    {

        public async Task AddToRoleAsync(User user, string roleName)

        {

            //throw new NotImplementedException();

        }

 

        public Task CreateAsync(User user)

        {

            throw new NotImplementedException();

        }

 

        public Task DeleteAsync(User user)

        {

            throw new NotImplementedException();

        }

 

        public void Dispose()

        {

            throw new NotImplementedException();

        }

 

        public async Task<User> FindByIdAsync(string userId)

        {

            return (User)new User()

            {

                FirstName = "Michael",

                UserName = "Michael Chi (DX)",

                Id = "michi@microsoft.com"

            }; throw new NotImplementedException();

        }

 

        public Task<User> FindByNameAsync(string userName)

        {

            var task = Task<User>.Run(() =>

            {

                return (User)new User()

                {

                    FirstName = "Michael",

                    UserName = "Michael Chi (DX)",

                    Id = "michi@microsoft.com"

                };

            });

 

            return task;

        }

 

        public async Task<IList<string>> GetRolesAsync(User user)

        {

            return new string[] { "Admin" };

        }

 

        public async Task<bool> IsInRoleAsync(User user, string roleName)

        {

            return true;

        }

 

        public Task RemoveFromRoleAsync(User user, string roleName)

        {

            throw new NotImplementedException();

        }

 

        public Task UpdateAsync(User user)

        {

            throw new NotImplementedException();

        }

    }

}

l   接著,新增一個UserManager.cs如下:

using System.Threading.Tasks;

using Microsoft.AspNet.Identity;

using Microsoft.Owin.Security;

using MyAuth.Models;

 

namespace MyAuth.Security

{

    public interface ISimpleUserManager

    {

        Task<User> FindAsync(string userName, string password);

        Task SignInAsync(User user, bool isPersistent);

        void SignOut();

 

        User FindById(string id);

    }

 

    public class SimpleUserManager : UserManager<User, string>, ISimpleUserManager

    {

        public User FindById(string id)

        {

            User user = new User

            {

                FirstName = "Michael",

                UserName = "Michael Chi (DX)",

                Id = "michi@microsoft.com"

            };

            return user;

        }

        private readonly IAuthenticationManager _authenticationManager;

 

        public SimpleUserManager(IAuthenticationManager authenticationManager)

            : base(new UserRoleStore())

        {

            _authenticationManager = authenticationManager;

        }

        public override Task<User> FindAsync(string userName, string password)

        {

            var task = Task<User>.Run(() =>

            {

                //var user = _userService.Authenticate(userName, password);

                User user = new User

                {

                    FirstName = "Michael",

                    UserName = "Michael Chi (DX)",

                    Id = "michi@microsoft.com"

                };

                return user;

            });

 

            return task;

        }

 

        public async Task SignInAsync(User user, bool isPersistent)

        {

            SignOut();

 

            var identity = await base.CreateIdentityAsync(user,

              DefaultAuthenticationTypes.ApplicationCookie);

            _authenticationManager.SignIn(

new AuthenticationProperties() {

IsPersistent = isPersistent }, identity);

        }

 

        public void SignOut()

        {

            _authenticationManager.SignOut();

        }

    }

}

l   最後,修改我們的AccountController.cs如下:

using Microsoft.AspNet.Identity;

using Microsoft.Owin.Security;

using MyAuth.Security;

using System.Collections.Generic;

using System.Security.Claims;

using System.Threading;

using System.Threading.Tasks;

using System.Web;

using System.Web.Http;

using System.Web.Mvc;

using System.Web.Security;

 

namespace Microsoft.Azure.Devices.Applications.RemoteMonitoring.DeviceAdmin.Web.Controllers

{

    [OutputCache(CacheProfile = "NoCacheProfile")]

    [System.Web.Mvc.OverrideAuthentication]

    [HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]

    public class AccountController : Controller

    {

        public async Task<ActionResult> SignIn()

        {

            IAuthenticationManager _authManager =

System.Web.HttpContext.Current

.GetOwinContext()

.Authentication;

 

 

            var manager = new SimpleUserManager(_authManager);

            var user = await manager.FindAsync

("<whatever user name>","<whatever password>");

 

            if (user != null)

            {

                //manager.AddToRole("michi@microsoft.com", "Admin");

                await manager.SignInAsync(user, isPersistent: true);

 

                if (User.Identity.IsAuthenticated)

                {

                    return RedirectToAction("Index", "Dashboard");

                }

                else

                {

                    return View();

                }

                           }

 

            return View();

 

          

        }

 

        // GET: SignOut

        public ActionResult SignOut()

        {

            HttpContext.GetOwinContext().Authentication.SignOut();

            return RedirectToAction("Index", "Dashboard");

        }

    }

}

實際跑跑看,可以發現確實我們的登入身分變成了程式裡面寫定的使用者了。

 

About Me