Authentication and authorization in. net)

Source: Internet
Author: User

Note: This article is intended for beginners. veterans may feel that there is no nutrition, so please bypass it.

 

"Authentication" and "Authorization" are concepts involved in almost all systems:

 

Authentication is to "determine whether a user has logged on? ", Like a Windows system, it cannot be used without Logon (whether you are using administrator or guest users, in short, you must log on correctly before entering the system ).

Authorization is "identity/role identification after a user logs on". For example, "administrator user" can install software, modify Windows Settings, and perform other operations after logging on to Windows, after a guest user logs on, only limited operations are required (for example, software installation is disabled ).

 

. Net corresponds to the "authentication" interface, while "Authorization" corresponds to the iprincipal interface. The two interfaces are defined in the namespace system. security. in principal:

using System;using System.Runtime.InteropServices;namespace System.Security.Principal{    [ComVisible(true)]    public interface IIdentity    {           string AuthenticationType { get; }           bool IsAuthenticated { get; }           string Name { get; }    }}

 

using System;using System.Runtime.InteropServices;namespace System.Security.Principal{    [ComVisible(true)]    public interface IPrincipal    {          IIdentity Identity { get; }          bool IsInRole(string role);    }}

It should be noted that the iprincipal Interface contains a read-only iidentity, which is also consistent with the concept mentioned at the beginning: the prerequisite for identity recognition is to log on first, and the identity can be further confirmed only after successful logon.

My friends who have used membership/role for Asp.net development should be familiar with the definition of these two interfaces. on the net page, how does one determine whether a user is logged on and the role?

Protected void page_load (Object sender, eventargs e) {httpcontext CTX = httpcontext. current; If (CTX. user. identity. isauthenticated & CTX. user. isinrole ("Administrator") {// What the administrator should do. Write it here} else {// hi. You are not the administrator! }}

This code is no longer familiar. That's right! The principle of membership/role is based on these two interfaces. If you have a question about httpcontext. Current. user, you can find the following definitions:

Httpcontext. Current. User is an instance of the iprincipal interface. With the above preparation knowledge, you can go straight to the topic. First, let's test the usage of a console program:

Using system; using system. security. principal; using system. threading; namespace consoletest {class program {static void main (string [] ARGs) {genericidentity _ identity = new genericidentity ("Yang Guo under the bodhi tree "); genericprincipal _ principal = new genericprincipal (_ identity, new string [] {"Administrator", "Website member"}); thread. currentprincipal = _ principal; // not required, but it is very useful in the winform Program (will be mentioned later) string loginname = _ principal. identity. n Ame; bool islogin = _ principal. identity. isauthenticated; bool isadmin = _ principal. isinrole ("Administrator"); bool iswebuser = _ principal. isinrole ("Website member"); console. writeline ("current user: {0}", loginname); console. writeline ("have you logged on? {0} ", islogin); console. writeline (" administrator? {0} ", isadmin); console. writeline (" Is it a Website member? {0} ", iswebuser); console. Read ();}}}

The output is as follows:

Current User: Yang Guo under the bodhi tree
Have you logged on? True
Administrator? True
Are website Members? True

Everything is normal, no big deal, but the console is only a single-threaded program by default, there is no rich GUI, so... this is just a warm-up. Let's see if several methods defined by the interface work.

These two interfaces can also be used in the winform program. The following will create a winform application with two windows: form1 and form2. You can use form1 as the logon interface, form2 is the main window of the program. In many management software, the main window must be accessed after logon. Let's simulate it:

Form1 interface:

Form2 is simpler: (a read-only textbox)

What I want to do: log on to form1 and check whether the user has logged on and identified the user in form2.

Code in form1:

Using system; using system. security. principal; using system. threading; using system. windows. forms; namespace winformtest {public partial class form1: FORM {public form1 () {initializecomponent ();} private void btnlogin_click (Object sender, eventargs e) {If (txtusername. text. trim () = "") {MessageBox. show ("Enter the user name! "); Txtusername. focus (); return;} iidentity _ identity = new genericidentity (txtusername. text. trim (); iprincipal _ principal = new genericprincipal (_ identity, new string [] {"Administrator"}); thread. currentprincipal = _ principal; // append it to the currentprincipal MessageBox of the current thread. show ("Logon successful! ");} Private void btnshow_click (Object sender, eventargs e) {(New form2 ()). showdialog ();} private void btnlogout_click (Object sender, eventargs e) {thread. currentprincipal = NULL; MessageBox. show ("exited! ");}}}

Code in form2:

Using system; using system. security. principal; using system. threading; using system. windows. forms; namespace winformtest {public partial class form2: FORM {public form2 () {initializecomponent ();} private void form2_load (Object sender, eventargs e) {iprincipal _ principal = thread. currentprincipal; If (_ principal. identity. isauthenticated) {This. textbox1.text = "you have logged on, current user:" + _ principal. identity. na Me; this. textbox1.text + = environment. newline + "current role:" + (_ principal. isinrole ("Administrator ")? "Administrator": "non-Administrator");} else {This. textbox1.text = "You have not logged on ";}}}}

Test: if you do not log on, Click Show Form 2. The result is as follows:

If you enter the user name, click "Log on", and then click "show Form 2", the result is as follows:

Ideal! In form2, you can directly determine whether a user is logged on and the role of the currently logged on user. Here is a key detail:

Thread. currentprincipal = _ principal; // append it to the currentprincipal of the current thread

In form1, append the _ principal after login to the currentprincipal of the current thread. We know that each program has a default main thread regardless of whether it is multi-thread or not. Therefore, after the currentprincipal of the main thread is associated with the _ principal after login, any other form can be directly used for judgment. If the judgment passes, this can be done in one way or another (including the creation of multiple threads for processing). If the judgment fails, the operation can be rejected.

 

After the winform problem is solved, consider webform. Of course, you can directly use. net2.0 supports the membership/role mechanism, but membership/role only supports sqlserver databases by default (Oracle can also be supported through membership provider for Oracle, but some databases are not supported, for example, access, MySQL, SQLite, DB2, etc.). If you do not want to save the username/password information in sqlserver (or even do not want to save it in a database, such as XML ), at this time, you have to start thinking.

 

Actually... even if membership/role is not used, the two interfaces mentioned above are still usable, but there is a problem: In winform, instances of the iprincipal interface can be stored in the memory until the program exits, so other windows can continue to access it for further judgment, but in webform, the page itself is stateless. Once the server outputs HTML to the browser of the client, the page of the client is no longer related to the server (you can even browse it offline, provided that the page is not refreshed ), so where is the final authentication information stored?

 

The answer is the browser cookie of the client! Therefore, the practices in webform are slightly different:

 

Create a webapplication with four new pages: Login. aspx, logout. aspx, default. aspx, gotourl. aspx. The functions of these four pages are as follows:

Login. aspx: logon page

Logout. aspx: used to process user logout (not required, but we recommend that you put the logout logic here so that you can reuse it wherever necessary)

Default. aspx: displayed after Logon

Gotourl. aspx: The page used for page jump after Logon (not required, but it is recommended to add)

 

Login. aspx code:

<% @ Page Language = "C #" autoeventwireup = "true" codebehind = "login. aspx. cs" inherits = "logintest. login" %> <! Doctype HTML public "-// W3C // dtd xhtml 1.0 transitional // en" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <HTML xmlns = "http://www.w3.org/1999/xhtml"> 

Post Code:

Using system; using system. web; using system. web. security; namespace logintest {public partial class login: system. web. UI. page {protected void page_load (Object sender, eventargs e) {} protected void button#click (Object sender, eventargs e) {string user = this.txt username. text; // read username string Password = this.txt password. text; // read the password if (validateuser (user, password) = true) // The validateuser method is used to verify the user combination Valid {// create a form to verify the ticket formsauthenticationticket ticket = new formsauthenticationticket (1, user, datetime. now, datetime. now. addminutes (30), true, "Administrator, member", "/"); // use the method defined in webcongfi to encrypt the serialized ticket as string hashticket = formsauthentication. encrypt (ticket); // convert the encrypted ticket to Cookie httpcookie usercookie = new httpcookie (formsauthentication. formscookiename, hashticket); // Add the cookie context to the client. response. cookies. add (Use Rcookie); // redirect response. Redirect ("gotourl. aspx? Returnurl = "+ server. urlencode ("default. aspx "));} else {// processing upon logon Failure }}/// <summary> /// verify that the user name/password is correct /// </Summary> /// <Param name = "username"> </param> // <Param name = "PWD"> </param> // <returns> </returns> private bool validateuser (string username, string PWD) {return true; // Of course, in actual development, You can query and verify in the database. Here is just an example }}}

Gotourl. aspx

using System;namespace LoginTest{    public partial class GotoUrl : System.Web.UI.Page    {        protected void Page_Load(object sender, EventArgs e)        {            string _returnUrl = Request["returnUrl"];            if (string.IsNullOrEmpty(_returnUrl))            {                _returnUrl = "~/default.aspx";            }            Response.Redirect(_returnUrl);        }    }}

The next step should be default. aspx. This is just a demonstration, so there is no post-code, and the logic of judgment is all written in default. aspx itself:

<% @ Page Language = "C #" autoeventwireup = "true" codebehind = "default. aspx. cs" inherits = "logintest. Default" %> <! Doctype HTML public "-// W3C // dtd xhtml 1.0 transitional // en" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <HTML xmlns = "http://www.w3.org/1999/xhtml"> 

The last one is to log out of the logout. ASPX page. Similarly, this page is only responsible for logging out the cookie ticket, so there is nothing on the interface, only the post code:

using System;using System.Web.Security;namespace LoginTest{    public partial class Logout : System.Web.UI.Page    {        protected void Page_Load(object sender, EventArgs e)        {            FormsAuthentication.SignOut();            Response.Redirect("default.aspx");        }    }}

If you have waited for F5 to see the final result, it may be disappointing:

I haven't logged on yet. I haven't even entered the user name or password. Why does it show that I have logged on? Do you think of Xiao Shenyang's classic line ~ What?

This is the difference between webform and winform. The default form authentication method of Asp.net is windows, so when the program runs, Asp.net regards the current Login User of windows as logged on, so we have to change the default "dummies" behavior of Asp.net and modify the web. config is as follows:

<?xml version="1.0"?><configuration>  <system.web>        <compilation debug="true" targetFramework="4.0" />           <authentication mode="Forms">      <forms         name=".ASPXAUTH"         loginUrl="login.aspx"         timeout="30"         path="/"         requireSSL="false"         domain="">      </forms>    </authentication>  </system.web></configuration>

Oh, I forgot to tell you that I am using Asp.net 4.0, so the Web. config display is very simple and refreshing.

OK. Run again:

This is the case. Click "Log on", go to login. aspx, and enter something in the user name (for example, "Yang Guo under the bodhi tree"). The following result is displayed:

Authentication successful! But there seems to be a problem: I didn't recognize my identity! (That is, the "Administrator, member" role specified by the code in login. aspx. CS)

 

Calm down and think about what the problem is?

In winform, we use

Iprincipal _ principal = new genericprincipal (_ identity, new string [] {"Administrator"}); thread. currentprincipal = _ principal; // append it to the currentprincipal of the current thread

Authorize _ principal as "Administrator" (of course, more roles can be assigned to it) and assign it to the currentprincipal of the thread, so it is OK, but there is no thread in webform. currentprincipal, and HTTP itself is stateless. In the next HTTP request, you cannot remember the status of the last request (as if every HTTP request is a new reincarnation, And you have forgotten it in your past ), fortunately, Microsoft developed a context concept for Asp.net. Although the HTTP protocol itself is stateless in a webapplication, an httpcontext context always exists when each ASPX page is requested, it can be used to retrieve memories of past lives, and httpcontext is mentioned at the beginning of the article. current. the user itself is iprincipal, and this is not thread. is the currentprincipal variant?

By the way, I would like to recall ASP. NET page lifecycle. Each ASPX page triggers the application_authenticaterequest event when requesting authentication, which is defined in global. in ascx, you can start with this:

Create a new global. ascx and open the post code. The content is as follows:

Using system; using system. security. principal; using system. web; using system. web. security; namespace logintest {public class Global: system. web. httpapplication {protected void application_start (Object sender, eventargs e) {} protected void session_start (Object sender, eventargs e) {} protected void application_beginrequest (Object sender, eventargs E) {}/// <summary> /// each ASPX page is triggered when authentication is required. /// </su Mmary> /// <Param name = "sender"> </param> // <Param name = "E"> </param> protected void application_authenticaterequest (Object sender, eventargs e) {httpcontext _ CTX = httpcontext. current; If (_ CTX. user! = NULL) {If (_ CTX. user. identity. isauthenticated = true) // authorized user (s) {formsidentity _ identity = (formsidentity) _ CTX. user. identity; string [] roles = _ identity. ticket. userdata. split (','); // set the role string, that is, login. aspx. in CS, "Administrator, member" is changed to array _ CTX. user = new genericprincipal (_ identity, roles); // generate a genericprincipal with the role information and assign it to the user, which is equivalent to thread in winform. currentprincipal = _ principal }}} protected void application_error (Object sender, eventargs e) {} protected void session_end (Object sender, eventargs e) {} protected void application_end (Object sender, eventargs e ){}}}

Test again and the result is normal:

 

And finally help. net advertisement :. net is a platform. Many of the technologies are universal across the platform (either winform or webform). We strongly recommend that you move closer to the standard model that comes with Microsoft as much as possible, in this way, the integration of different types of applications is very convenient, and the compatibility is good and easy to upgrade.

It is often seen that a method (such as setting a global static variable to determine whether the user has logged on) is adopted in winform ), then, the webform has a lot of brains to think about one method (for example, creating a user table by yourself, developing an encryption algorithm, and then using session for judgment). If the two applications need to be integrated in the future, it is estimated that it will take a lot of effort (of course, there are also well-designed ones, considering future expansion in the first place, but after all this is a minority, and it is relatively demanding on programmers ), however, if you use the standard model (iidentity, iprincipal) mentioned in this article, it is very convenient to integrate these two applications.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.