ASP.NET MVC Forms検証メカニズム
10345 ワード
ASP.NET MVC 3
Forms認証の使用
認証プロセス
一、ユーザーログイン
1、検証フォーム:ModelState.IsValid
2、ユーザー名とパスワードの検証:データベースを検索して検証する
3、ユーザー名とパスワードが正しい場合、クライアントでCookieを保存してユーザーログイン状態を保存する:SetAuthCookie
1):データベースからユーザ名と必要な情報を検出し、追加情報をUserDataに保存する
2):ユーザー名とUserDataをFormsAuthenticationTicket手形に保存する
3):手形を暗号化するEncrypt
4):暗号化されたチケットをCookieに保存してクライアントに送信
4、ログイン前のページにジャンプ
二、ログインの検証
1.GlobalにPostAuthenticateRequestイベント関数を登録し、クライアントから送られてきたCookieデータを解析する
1):HttpContext.Current.User.Identityユーザーがログインしているかどうかを判断する(FormsIdentity,IsAuthenticated,AuthenticationType)
2):HttpContextのRequestのCookieからValueを解析し,復号してFormsAuthenticationTicketからUserDataを得る
2、ロール検証
ActionにAuthorizeプロパティを追加すると、ロール検証が可能になります.
HttpContext.Current.UserのIsInRoleメソッドによるロール認証(書き換えが必要)
次はコードです.以上使用したすべての検証クラスが再ロードされます.
一、まずユーザユーザ認証のIPrincipal
ここでは汎用属性を抽象化し,2つのIPrincipalを定義する
では、4つのクラス定義が完了しました.次は
1、まずは上陸
二、ログイン完了後、検証であり、検証前にクライアントのユーザデータを取得する(前に設定したCookieから解析)
グローバルファイル:Global.asaxに次のコードを追加
これによりRequestからUserDataが解析され,以下で検証に用いることができる.
三、ロール検証が必要なアクションに[MyAuthorize]特性を追加する
Forms認証の使用
認証プロセス
一、ユーザーログイン
1、検証フォーム:ModelState.IsValid
2、ユーザー名とパスワードの検証:データベースを検索して検証する
3、ユーザー名とパスワードが正しい場合、クライアントでCookieを保存してユーザーログイン状態を保存する:SetAuthCookie
1):データベースからユーザ名と必要な情報を検出し、追加情報をUserDataに保存する
2):ユーザー名とUserDataをFormsAuthenticationTicket手形に保存する
3):手形を暗号化するEncrypt
4):暗号化されたチケットをCookieに保存してクライアントに送信
4、ログイン前のページにジャンプ
二、ログインの検証
1.GlobalにPostAuthenticateRequestイベント関数を登録し、クライアントから送られてきたCookieデータを解析する
1):HttpContext.Current.User.Identityユーザーがログインしているかどうかを判断する(FormsIdentity,IsAuthenticated,AuthenticationType)
2):HttpContextのRequestのCookieからValueを解析し,復号してFormsAuthenticationTicketからUserDataを得る
2、ロール検証
ActionにAuthorizeプロパティを追加すると、ロール検証が可能になります.
HttpContext.Current.UserのIsInRoleメソッドによるロール認証(書き換えが必要)
次はコードです.以上使用したすべての検証クラスが再ロードされます.
一、まずユーザユーザ認証のIPrincipal
ここでは汎用属性を抽象化し,2つのIPrincipalを定義する
//
public class MyFormsPrincipal<TUserData> : IPrincipal
where TUserData : class, new()
{
//
public IIdentity Identity { get; private set; }
//
public TUserData UserData { get; private set; }
public MyFormsPrincipal(FormsAuthenticationTicket ticket, TUserData userData)
{
if (ticket == null)
throw new ArgumentNullException("ticket");
if (userData == null)
throw new ArgumentNullException("userData");
Identity = new FormsIdentity(ticket);
UserData = userData;
}
//
public bool IsInRole(string role)
{
var userData = UserData as MyUserDataPrincipal;
if (userData == null)
throw new NotImplementedException();
return userData.IsInRole(role);
}
//
public bool IsInUser(string user)
{
var userData = UserData as MyUserDataPrincipal;
if (userData == null)
throw new NotImplementedException();
return userData.IsInUser(user);
}
}
汎用エンティティには、データエンティティを格納し、ロール検証とユーザー検証を特定のデータエンティティに格納できます.//
public class MyUserDataPrincipal : IPrincipal
{
//
private readonly MingshiEntities mingshiDb = new MingshiEntities();
public int UserId { get; set; }
//
public List<int> RoleId { get; set; }
// Authorize ,
public bool IsInRole(string role)
{
//
var userroles = mingshiDb.UserRole.Where(u => u.UserId == UserId).Select(u => u.Role.RoleName).ToList();
var roles = role.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
return (from s in roles from userrole in userroles where s.Equals(userrole) select s).Any();
}
//
public bool IsInUser(string user)
{
//
var users = user.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return mingshiDb.User.Any(u => users.Contains(u.UserName));
}
[ScriptIgnore] //
public IIdentity Identity { get { throw new NotImplementedException(); } }
}
二、Cookieの検証と設定のためのFormsAuthentication//
public class MyFormsAuthentication<TUserData> where TUserData : class, new()
{
//Cookie
private const int CookieSaveDays = 14;
// Cookie
public static void SetAuthCookie(string username, TUserData userData, bool rememberMe)
{
if (userData == null)
throw new ArgumentNullException("userData");
var data = (new JavaScriptSerializer()).Serialize(userData);
// ticket
var ticket = new FormsAuthenticationTicket(
2, username, DateTime.Now, DateTime.Now.AddDays(CookieSaveDays), rememberMe, data);
// ticket
var cookieValue = FormsAuthentication.Encrypt(ticket);
// Cookie
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue)
{
HttpOnly = true,
Secure = FormsAuthentication.RequireSSL,
Domain = FormsAuthentication.CookieDomain,
Path = FormsAuthentication.FormsCookiePath,
};
if (rememberMe)
cookie.Expires = DateTime.Now.AddDays(CookieSaveDays);
// Cookie
HttpContext.Current.Response.Cookies.Remove(cookie.Name);
HttpContext.Current.Response.Cookies.Add(cookie);
}
// Request Ticket,UserData
public static MyFormsPrincipal<TUserData> TryParsePrincipal(HttpRequest request)
{
if (request == null)
throw new ArgumentNullException("request");
// 1. Cookie
var cookie = request.Cookies[FormsAuthentication.FormsCookieName];
if (cookie == null || string.IsNullOrEmpty(cookie.Value)) return null;
try
{
// 2. Cookie , FormsAuthenticationTicket
var ticket = FormsAuthentication.Decrypt(cookie.Value);
if (ticket != null && !string.IsNullOrEmpty(ticket.UserData))
{
var userData = (new JavaScriptSerializer()).Deserialize<TUserData>(ticket.UserData);
if (userData != null)
{
return new MyFormsPrincipal<TUserData>(ticket, userData);
}
}
return null;
}
catch
{
/* , 。 */
return null;
}
}
}
三、ロールとユーザー名を検証するためのAuthorize特性//
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
{
var user = httpContext.User as MyFormsPrincipal<MyUserDataPrincipal>;
if (user != null)
return (user.IsInRole(Roles) || user.IsInUser(Users));
return false;
}
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
// , , : , Action
filterContext.Result = new RedirectResult("http://www.baidu.com");
}
}
では、4つのクラス定義が完了しました.次は
1、まずは上陸
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
//
var bll= new UserBll();
var userId = bll.Validate(model.UserName, model.Password, HttpContext.Request.UserHostAddress, HttpContext.Request.UserAgent);
if (userId > 0)
{
// , , ( , Id)
var userData = new MyUserDataPrincipal {UserId = userId};
// Cookie
MyFormsAuthentication<MyUserDataPrincipal>.SetAuthCookie(model.UserName, userData, model.RememberMe);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", " 。");
}
}
// ,
return View(model);
}
二、ログイン完了後、検証であり、検証前にクライアントのユーザデータを取得する(前に設定したCookieから解析)
グローバルファイル:Global.asaxに次のコードを追加
protected void Application_PostAuthenticateRequest(object sender, System.EventArgs e)
{
var formsIdentity = HttpContext.Current.User.Identity as FormsIdentity;
if (formsIdentity != null && formsIdentity.IsAuthenticated && formsIdentity.AuthenticationType == "Forms")
{
HttpContext.Current.User =
MyFormsAuthentication<MyUserDataPrincipal>.TryParsePrincipal(HttpContext.Current.Request);
}
}
これによりRequestからUserDataが解析され,以下で検証に用いることができる.
三、ロール検証が必要なアクションに[MyAuthorize]特性を追加する
[MyAuthorize(Roles = "User", Users = "bomo,toroto")]
public ActionResult About()
{
return View();
}
ユーザがこのアクションにアクセスすると、MyAuthorizeのAuthorizeCoreメソッドを呼び出して検証し、検証に成功した場合は実行を続行し、検証に失敗した場合はHandleUnauthorizedRequestメソッドを呼び出して対応する処理を行い、ここで定義したRolesとUsersをMyAuthorizeで取得して検証する