今天要介绍在 Web API 使用 表单验证 (FormsAuthentication)
进行授权验证。
常见的验证机制主要分为两类:
Cookie-Based Authentication: 使用浏览器的 Cookie 储存使用者验证资讯,此类验证方式很早就有了,大部分网站的登入机制都是此类。
Token-Based Authentication: 使用 Token 储存使用者验证资讯,Token 为一串加密文字,较 Cookie 灵活,可用于不支援 Cookie 的装置上,这种验证方式较新,主要是近几年 APP 和社群网站兴起,用于 API 的授权和验证。
本篇会介绍第一种方式,Cookie-Based 虽然比较旧,但还是很好用的网站登入机制且较 Token-Based 简单,之后有机会再介绍 Token-Based,我自己也还没实作过,蛮想玩看看的。
下图为网站登入流程图。
浏览器每次和 API 请求资料,都需要先验证 Cookie 资讯,判断使用者是否具有资料的存取权限。
实作
新增 Identity
列举 (Enum) 管理使用者身分,使用 Enum 的优点 另一篇 文章有详细说明,这里就不再赘述。
public enum Identity{ [Description("管理者")] Admin = 1, [Description("一般使用者")] User = 2,}
新增 User
类别定义要存入 Cookie 的资讯。
public class User{ //流水号 public int Id { get; set; } //帐号 public string UserId { get; set; } //名称 public string UserName { get; set; } //身分 public Identity Identity { get; set; }}
新增 AuthManager
类别管理登入、登出和取得使用者资讯的操作。
public class AuthManager{ //登入 public void SignIn(User user) { //新增表单验证用的票证 var ticket = new FormsAuthenticationTicket(1, //版本 //使用者名称 user.UserName, //发行时间 DateTime.Now, //有效期限 DateTime.Now.AddMinutes(60), //是否将 Cookie 设定成 Session Cookie,如果是则会在浏览器关闭后移除 false, //将要记录的使用者资讯转换为 JSON 字串 JsonConvert.SerializeObject(user), //储存 Cookie 的路径 FormsAuthentication.FormsCookiePath); //将 Ticket 加密 var encTicket = FormsAuthentication.Encrypt(ticket); //将 Ticket 写入 Cookie HttpContext.Current.Response.Cookies.Add( new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)); } //登出 public void SignOut() { //移除浏览器的表单验证 FormsAuthentication.SignOut(); } //取得使用者资讯 public User GetUser() { //取得 ASP.NET 使用者 var user = HttpContext.Current.User; //是否通过验证 if (user?.Identity?.IsAuthenticated == true) { //取得 FormsIdentity var identity = (FormsIdentity)user.Identity; //取得 FormsAuthenticationTicket var ticket = identity.Ticket; //将 Ticket 内的 UserData 解析回 User 物件 return JsonConvert.DeserializeObject<User>(ticket.UserData); } return null; }}
新增 SignInViewModel
类别接收传回的帐号和密码,ViewModel 的功能是接收前端传回的资料,或回传资料给前端,作为内部和外部沟通的桥樑。
public class SignInViewModel{ //帐号 public string UserId { get; set; } //密码 public string Password { get; set; }}
新增 AuthController
测试登入和登出相关功能。
[RoutePrefix("api/auth")]public class AuthController : ApiController{ private AuthManager _authManager; public AuthController() { _authManager = new AuthManager(); } //登入 [HttpPost] [Route("signIn")] public void SignIn(SignInViewModel model) { //模拟从资料库取得资料 if (!(model.UserId == "abc" && model.Password == "123")) { throw new Exception("登入失败,帐号或密码错误"); } var user = new User { Id = 1, UserId = "abc", UserName = "小明", Identity = Identity.User }; _authManager.SignIn(user); } //登出 [HttpPost] [Route("signOut")] public void SignOut() { _authManager.SignOut(); } //测试是否通过验证 [HttpPost] [Route("isAuthenticated")] public bool IsAuthenticated() { var user = _authManager.GetUser(); if (user == null) { return false; } return true; }}
最后要在 Web.config 内加入 <authentication mode="Forms" />
才会启用表单验证。
<configuration> <system.web> <!--启用Form认证--> <authentication mode="Forms" /> </system.web></configuration>
测试
接着使用 Postman 测试。
1.登入
api/auth/signIn
.ASPXAUTH
就是表单验证使用的 Cookie。
2.是否通过验证
api/auth/isAuthenticated
回传 true 表示成功登入。
3.登出
api/auth/signOut
可以看到 Cookie 少了一个,.ASPXAUTH
被清除了。
4.是否通过验证
api/auth/isAuthenticated
回传 false 表示成功登出。
结语
表单验证帮我们处理了加解密和 Cookie 的操作,因此很容易就完成了网站的登入机制,AuthManager 使用 JSON 储存使用者资讯,JSON 容易扩展,未来如需增加 Cookie 资讯,只需对 User 类别新增栏位即可,不过还是要注意 Cookie 的长度限制,各家浏览器不太一样,大概是 4K 左右,今天就介绍到这里,感谢大家观看。
参考文章
[ASP.NET WebApi]使用JWT进行web api验证
浅谈使用Json Web Token和Cookie的利弊
简介 ASP.NET 表单验证 (FormsAuthentication) 的运作方式
ASP.NET 自订角色的方式(不用实做 Role Provider)
[ASP.net MVC] ASP.net MVC整合FormsAuthentication表单验证登入 - 简易範例程式码
请问有关Context.User.Identity 与 Request.IsAuthenticated 之间的问题
UserManager(Of TUser) 类别