今天要介紹在 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) 類別
如何測試http://localhost/WebAPITest/api/auth/signIn
我測試都出現{
"Message": "要求的資源不支援 http 方法 'GET'。"
}
如何解決
送出的請求要選擇 POST 方法
方便請教一下,是 用哪個瀏覽器嗎?
如何出現選擇post的畫面。
謝謝,我發現是用postman測試了,謝謝您
是的,我是用 Postman 測試。
請教一下if (user?.Identity?.IsAuthenticated == true)
?.是什麼意思,為何多一個?
C# 的 Null 條件運算子
,相當於。
if (user != null &&
user.Identity != null &&
user.Identity.IsAuthenticated == true)