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;刪除或Mark掉app.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");
}
}
}
實際跑跑看,可以發現確實我們的登入身分變成了程式裡面寫定的使用者了。