In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
This article mainly introduces ASP.NET MVC how to achieve Form form verification, has a certain reference value, interested friends can refer to, I hope you can learn a lot after reading this article, the following let Xiaobian take you to understand.
I. Preface
There have been a lot of articles about form validation, which I believe Web developers have basically written, which have recently been used in a personal project. I'd like to share them with you here. Originally wanted to start from the user registration, but found a lot of things, involving the interface, front-end authentication, front-end encryption, background decryption, user password Hash, rights verification and so on, the article may be very long, so here is the main introduction of login authentication and access control part, interested friends are welcome to communicate.
General verification methods include Windows validation and form validation, while web projects use more form validation. The principle is very simple. To put it simply, using the cookie of the browser, the authentication token is stored on the client browser, and the cookie is sent to the server with the request each time, and the server verifies the token. Usually, users of a system can be divided into multiple roles: anonymous users, ordinary users and administrators, which can be subdivided, for example, users can be ordinary users or Vip users, administrators can be ordinary administrators or super administrators, and so on. In the project, some of our pages may only allow administrators to view, some may only allow login users to view, this is role differentiation (Roles); in some special cases, some pages may only allow people with the name "Zhang San" to view, which is user differentiation (Users).
Let's take a look at the final effect to be achieved:
1. This is control at the Action level.
Public class Home1Controller: Controller {/ / Anonymous access public ActionResult Index () {return View ();} / / Login user visits [RequestAuthorize] public ActionResult Index2 () {return View ();} / / Login user can visit [RequestAuthorize (Users= "Zhang San")] public ActionResult Index3 () {return View () } / / Administrator visits [RequestAuthorize (Roles= "Admin")] public ActionResult Index4 () {return View ();}}
two。 This is control at the Controller level. Of course, if an Action requires anonymous access, it is also allowed, because at the control level, Action takes precedence over Controller.
/ / permission control at Controller level [RequestAuthorize (User= "Zhang San")] public class Home2Controller: Controller {/ / login users access public ActionResult Index () {return View ();} / allow anonymous access to [AllowAnonymous] public ActionResult Index2 () {return View ();}}
3.Area level control. Sometimes we partition some modules, of course, we can also mark them in Area's Controller and Action.
As you can see from the above, we need to mark permissions everywhere, and it is not a good practice to write Roles and Users in the program. I wish it could be simpler and explained in the configuration file. For example, the configuration is as follows:
Admin Zhang San Zhang San Admin
It is written in the configuration file for ease of management, and if it is also written in the program, the configuration file will be overwritten. Ok, let's get down to business.
II. Main interfaces
Let's first look at the two main interfaces used.
IPrincipal defines the basic functions of user objects. The APIs are defined as follows:
Public interface IPrincipal {/ / identify object IIdentity Identity {get;} / / determine whether the current role belongs to the specified role bool IsInRole (string role);}
It has two main members, IsInRole is used to determine whether the current object belongs to the specified role, and IIdentity defines the identification object information. The User property of HttpContext is of type IPrincipal.
IIdentity defines the basic functions of identifying objects. APIs are defined as follows:
Public interface IIdentity {/ / authentication type string AuthenticationType {get;} / / whether the authentication passed bool IsAuthenticated {get;} / / username string Name {get;}}
IIdentity contains some user information, but sometimes we need to store more information, such as user ID, user role, and so on. The information will be encrypted and saved in cookie. When the verification is passed, it can be decoded and deserialized, and the state can be saved. For example, define a UserData.
Public class UserData: IUserData {public long UserID {get; set;} public string UserName {get; set;} public string UserRole {get; set;} public bool IsInRole (string role) {if (string.IsNullOrEmpty (role)) {return true;} return role.Split (',') .any (item = > item.Equals (this.UserRole, StringComparison.OrdinalIgnoreCase)) } public bool IsInUser (string user) {if (string.IsNullOrEmpty (user)) {return true;} return user.Split (',') .Any (item = > item.Equals (this.UserName, StringComparison.OrdinalIgnoreCase));}}
UserData implements the IUserData interface, which defines two methods: IsInRole and IsInUser, which are used to determine whether the current user role and user name meet the requirements, respectively. The interface is defined as follows:
Public interface IUserData {bool IsInRole (string role); bool IsInUser (string user);} next defines a Principal implementation IPrincipal interface, as follows: public class Principal: IPrincipal {public IIdentity Identity {get;private set;} public IUserData UserData {get;set;} public Principal (FormsAuthenticationTicket ticket, IUserData userData) {EnsureHelper.EnsureNotNull (ticket, "ticket"); EnsureHelper.EnsureNotNull (userData, "userData"); this.Identity = new FormsIdentity (ticket); this.UserData = userData } public bool IsInRole (string role) {return this.UserData.IsInRole (role);} public bool IsInUser (string user) {return this.UserData.IsInUser (user);}}
Principal contains IUserData instead of a specific UserData, so it's easy to replace a UserData without affecting other code. Principal's IsInRole and IsInUser indirectly call the IUserData's method of the same name.
Write cookie and read cookie
Next, all you need to do is create a UserData after the user has successfully logged in, serialize it, encrypt it with FormsAuthentication, and write it to cookie; when the request arrives, you need to try to decrypt and deserialize the cookie. As follows:
Public class HttpFormsAuthentication {public static void SetAuthenticationCookie (string userName, IUserData userData, double rememberDays = 0) {EnsureHelper.EnsureNotNullOrEmpty (userName, "userName"); EnsureHelper.EnsureNotNull (userData, "userData"); EnsureHelper.EnsureRange (rememberDays, "rememberDays", 0); / / Information string userJson = JsonConvert.SerializeObject (userData) saved in cookie; / / create user ticket double tickekDays = rememberDays = 0? 7: rememberDays Var ticket = new FormsAuthenticationTicket (2, userName, DateTime.Now, DateTime.Now.AddDays (tickekDays), false, userJson); / / FormsAuthentication provides web forms authentication service / / encryption string encryptValue = FormsAuthentication.Encrypt (ticket); / / create cookie HttpCookie cookie = new HttpCookie (FormsAuthentication.FormsCookieName, encryptValue); cookie.HttpOnly = true; cookie.Domain = FormsAuthentication.CookieDomain If (rememberDays > 0) {cookie.Expires = DateTime.Now.AddDays (rememberDays);} HttpContext.Current.Response.Cookies.Remove (cookie.Name); HttpContext.Current.Response.Cookies.Add (cookie);} public static Principal TryParsePrincipal (HttpContext context) where TUserData: IUserData {EnsureHelper.EnsureNotNull (context, "context"); HttpRequest request = context.Request; HttpCookie cookie = request.Cookies [FormsAuthentication.FormsCookieName] If (cookie = = null | | string.IsNullOrEmpty (cookie.Value)) {return null;} / / decryption cookie value FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt (cookie.Value); if (ticket = = null | | string.IsNullOrEmpty (ticket.UserData)) {return null;} IUserData userData = JsonConvert.DeserializeObject (ticket.UserData); return new Principal (ticket, userData);}}
When logging in, we can do something like this:
Public ActionResult Login (string userName,string password) {/ / verify some logic such as username and password. UserData userData = new UserData () {UserName = userName, UserID = userID, UserRole = "Admin"}; HttpFormsAuthentication.SetAuthenticationCookie (userName, userData, 7); / / passed.}
After the login is successful, the information is written to cookie, and the request can be viewed through the browser, and there will be a Cookie named "Form" (you also need to simply configure the configuration file). Its value is an encrypted string, and subsequent requests are verified against this cookie request. To do this, call the above TryParsePrincipal in the AuthenticateRequest verification event of HttpApplication, such as:
Protected void Application_AuthenticateRequest (object sender, EventArgs e) {HttpContext.Current.User = HttpFormsAuthentication.TryParsePrincipal (HttpContext.Current);}
Here, if the verification fails, HttpContext.Current.User is null, indicating that the current user is not identified. But you can't do anything about permissions here, because as mentioned above, some pages are allowed to be accessed anonymously.
III. AuthorizeAttribute
This is a Filter, executed before the Action is executed, which implements the IActionFilter interface. About Filter, you can read my previous article, which will not be introduced here. We define a RequestAuthorizeAttribute inheriting AuthorizeAttribute and override its OnAuthorization method. If a Controller or Action marks this feature, then the method is executed before the Action is executed, where it is determined whether it is logged in and has permissions, and if not, deal with it accordingly. The specific code is as follows:
[AttributeUsage (AttributeTargets.Class | AttributeTargets.Method)] public class RequestAuthorizeAttribute: AuthorizeAttribute {/ / verify public override void OnAuthorization (AuthorizationContext context) {EnsureHelper.EnsureNotNull (context, "httpContent"); / / whether to allow anonymous access to if (context.ActionDescriptor.IsDefined (typeof (AllowAnonymousAttribute), false) {return;} / / login verification Principal principal = context.HttpContext.User as Principal; if (principal = null) {SetUnAuthorizedResult (context) HandleUnauthorizedRequest (context); return;} / / if (! principal.IsInRole (base.Roles) | |! principal.IsInUser (base.Users)) {SetUnAuthorizedResult (context); HandleUnauthorizedRequest (context); return;} / / verify profile if (! ValidateAuthorizeConfig (principal, context)) {SetUnAuthorizedResult (context); HandleUnauthorizedRequest (context); return }} / / private void SetUnAuthorizedResult (AuthorizationContext context) {HttpRequestBase request = context.HttpContext.Request; if (request.IsAjaxRequest ()) {/ / process ajax request string result = JsonConvert.SerializeObject (JsonModel.Error (403)); context.Result = new ContentResult () {Content = result} } else {/ / Jump to login page string loginUrl = FormsAuthentication.LoginUrl + "? ReturnUrl=" + preUrl; context.Result = new RedirectResult (loginUrl);}} / / override protected override void HandleUnauthorizedRequest (AuthorizationContext filterContext) {if (filterContext.Result! = null) {return;} base.HandleUnauthorizedRequest (filterContext);}}
Note: the code here is extracted from the personal project, abbreviated part of the code, some are auxiliary classes, the code is not posted, but should not affect reading.
1. If the IPrincipal we get in the AuthenticateRequest event of HttpApplication is null, then the validation fails.
two。 If the validation passes, the program validates the Roles and User properties of the AuthorizeAttribute.
3. If the verification passes, the program validates the corresponding Roles and Users properties in the configuration file.
The method to verify the configuration file is as follows:
Private bool ValidateAuthorizeConfig (Principal principal, AuthorizationContext context) {/ / action may be overloaded. When overloaded, ActionName should be marked as ActionNameAttribute actionNameAttr = context.ActionDescriptor .GetCustomAttributes (typeof (ActionNameAttribute), false) .OfType (). FirstOrDefault (); string actionName = actionNameAttr = = null? Null: actionNameAttr.Name; AuthorizationConfig ac = ParseAuthorizeConfig (actionName, context.RouteData); if (ac! = null) {if (! principal.IsInRole (ac.Roles)) {return false;} if (! principal.IsInUser (ac.Users)) {return false;}} return true;} private AuthorizationConfig ParseAuthorizeConfig (string actionName, RouteData routeData) {string areaName = routeData.DataTokens ["area"] as string String controllerName = null; object controller, action; if (string.IsNullOrEmpty (actionName)) {if (routeData.Values.TryGetValue ("action", out action)) {actionName = action.ToString ();}} if (routeData.Values.TryGetValue ("controller", out controller)) {controllerName = controller.ToString () } if (! string.IsNullOrEmpty (controllerName) & &! string.IsNullOrEmpty (actionName)) {return AuthorizationConfig.ParseAuthorizationConfig (areaName, controllerName, actionName);} return null;}}
As you can see, it is validated by an AuthorizationConfig class based on the area, controller, and action names of the current request, which is defined as follows:
Public class AuthorizationConfig {public string Roles {get; set;} public string Users {get; set;} private static XDocument _ doc; / / configuration file path private static string _ path = "~ / Identity/Authorization.xml"; / / load configuration file static AuthorizationConfig () {string absPath = HttpContext.Current.Server.MapPath (_ path) for the first time; if (File.Exists (absPath)) {_ doc = XDocument.Load (absPath) }} / / parse the configuration file to get the information public static AuthorizationConfig ParseAuthorizationConfig (string areaName, string controllerName, string actionName) {EnsureHelper.EnsureNotNullOrEmpty (controllerName, "controllerName"); EnsureHelper.EnsureNotNullOrEmpty (actionName, "actionName"); if (_ doc = = null) {return null;} XElement rootElement = _ doc.Element ("root"); if (rootElement = null) {return null } AuthorizationConfig info = new AuthorizationConfig (); XElement rolesElement = null; XElement usersElement = null; XElement areaElement = rootElement.Elements ("area") .Where (e = > CompareName (e, areaName)) .FirstOrDefault (); XElement targetElement = areaElement? RootElement; XElement controllerElement = targetElement.Elements ("controller") .Where (e = > CompareName (e, controllerName)). FirstOrDefault (); / / if there are no area nodes and controller nodes, return null if (areaElement = = null & & controllerElement = = null) {return null;} / / get the area if of the tag (controllerElement = = null) {rootElement = areaElement.Element ("roles"); usersElement = areaElement.Element ("users") } else {XElement actionElement = controllerElement.Elements ("action") .Where (e = > CompareName (e, actionName)) .FirstOrDefault (); if (actionElement! = null) {/ / get the rolesElement = actionElement.Element ("roles") of the tag action at this time; usersElement = actionElement.Element ("users") } else {/ / get rolesElement = controllerElement.Element ("roles") of the tag controller at this time; usersElement = controllerElement.Element ("users");}} info.Roles = rolesElement = = null? Null: rolesElement.Value; info.Users = usersElement = = null? Null: usersElement.Value; return info;} private static bool CompareName (XElement e, string value) {XAttribute attribute = e.Attribute ("name"); if (attribute = = null | | string.IsNullOrEmpty (attribute.Value)) {return false;} return attribute.Value.Equals (value, StringComparison.OrdinalIgnoreCase);}
The code here is long, but the main logic is to parse the configuration information at the beginning of the article.
Briefly summarize the steps of the program implementation:
1. After verifying the user name and password correctly, call SetAuthenticationCookie to write some status information to cookie.
two。 In the Authentication event of HttpApplication, call TryParsePrincipal to get the status information.
3. The RequestAuthorizeAttribute feature is marked on the Action (or Controller) that needs to be verified, and the settings Roles and Users;Roles and Users can also be configured in the configuration file.
4. Validation and permission logic processing are performed in the OnAuthorization method of RequestAuthorizeAttribute.
Thank you for reading this article carefully. I hope the article "how to achieve Form form validation in ASP.NET MVC" shared by the editor will be helpful to everyone. At the same time, I also hope that you will support and pay attention to the industry information channel. More related knowledge is waiting for you to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.