JWT-based Web API authentication and cross-domain invocation practices

Source: Internet
Author: User

With the advent of multi-terminal, more and more sites through the Web API restful form of external services, many sites are also used in front-end separation mode for development, so in the way of authentication may be different from the traditional cookie-based session ID practice, In addition to the annoying problem of submitting cookies across domains, more importantly, some endpoints may not support cookies at all.

The Json Web Token (JWT) is a good authentication and authorization scheme, simply to verify the caller's authorization information when invoking the API with a Token issued by the API side.
However, due to the time relationship, do not describe the JWT more, please refer to Jwt.io

Here is a JWT-based authentication of the ASP. Demo, in order to simulate the development of front-end separation, the demo contains a static page site (the path in IIS is http://localhost:8057) and a Web API site ( http://localhost:8056). The static page site has only one index.html, which includes a login feature and two functions that call the interface that requires authentication to obtain data, all of which are called through Ajax.

Here are the main code that needs to be written, so let's step through the code.

Developing the Login interface

Since we used the JWT technology, we added a framework that encapsulates the JWT used first on NuGet. I used the following framework.

According to JWT definition, the data segment that hosts user identity information in a JWT is called payload. There is a need to create a class "AuthInfo" to represent payload.

    /// <summary>    ///represents the payload of a JWT/// </summary>     Public classAuthInfo {/// <summary>        ///User name/// </summary>         Public stringUserName {Get;Set; } /// <summary>        ///A list of roles that can be used to record the user's role, equivalent to the concept of claims (if you are not sure what claim, please Google "claims-based permission control")/// </summary>         Publiclist<string> Roles {Get;Set; } /// <summary>        ///whether it is an administrator/// </summary>         Public BOOLISAdmin {Get;Set; }

Then write the login interface

  Public classLogincontroller:apicontroller { Publicloginresult Post ([frombody]loginrequest request) {Loginresult rs=NewLoginresult (); //Suppose the username is "admin" and the password is "123"            if(Request. UserName = ="Admin"&& request. Password = ="123")            {                //If the user is logged on successfully, the user's identity data can be obtained. Of course, in actual development, it is necessary to obtain the user's role and permissions in the database .AuthInfo AuthInfo =NewAuthInfo {isadmin=true, Roles=Newlist<string> {"Admin","owner"}, UserName="Admin"                }; Try                {                    //The build Token,securekey is a configured web. config that is used to encrypt token keys, and to kill and not to tell anyone                    byte[] key = Encoding.Default.GetBytes (configurationmanager.appsettings["SecureKey"]); //using HS256 encryption algorithm                    stringtoken =JWT. Jsonwebtoken.encode (AuthInfo, Key, JWT.)                    JWTHASHALGORITHM.HS256); Rs. Token=token; Rs. Success=true; }                Catch{Rs. Success=false; Rs. Message="Login Failed"; }            }            Else{Rs. Success=false; Rs. Message="The user name or password is incorrect"; }            returnrs; }    }

In this connection, we have written the login interface. If the username and password are correct, the login interface generates a token containing the user's identity information as a response. Once the token is received by the front end, the token will be included in subsequent requests to prove its identity.

Authorizeattribute

Next, we need to write code about permission control and token parsing.

The Web API framework provides authorizeattribute to validate requests before invoking the API, and to customize the validation logic by overriding the Authorizeattribute.isauthorized method

 Public classApiauthorizeattribute:authorizeattribute {protected Override BOOLisauthorized (Httpactioncontext actioncontext) {//The front-end request API will store tokens in the request header named "Auth"            varAuthheader = fromHinchActionContext.Request.HeaderswhereH.key = ="Auth" SelectH.value.firstordefault (); if(Authheader! =NULL)            {                stringtoken =Authheader.firstordefault (); if(!string. IsNullOrEmpty (token)) {Try                    {                        //to decrypt token                        stringSecureKey = system.configuration.configurationmanager.appsettings["SecureKey"]; AuthInfo AuthInfo= JWT. Jsonwebtoken.decodetoobject<authinfo>(token, securekey); if(AuthInfo! =NULL)                        {                            //the user information is stored for subsequent calls .ACTIONCONTEXT.REQUESTCONTEXT.ROUTEDATA.VALUES.ADD ("Auth", AuthInfo); return true; }                        Else                            return false; }                    Catch                    {                        return false; }                }                Else                    return false; }            Else                return false; }    }

Write an interface that is protected by authorizeattribute, assuming that the interface returns sensitive information that is relevant to the user.

It is important to note that because the front-end site and the Web API site use different ports, even the scheme (HTTP) and address are the same, but still cause cross-domain access. Therefore, cross-domain access must be enabled on the Web API site. In fact, cors (cross-domain resource sharing) or so-called same origin policy (same-origin policies) is a concept on the browser, and the server needs only to return a few response headers as needed:
Access-control-allow-origin: Indicates that the site is allowed access by those sources (domains)
Access-control-allow-headers: Indicates that the site allows those custom request headers (we send a request header with token named "Auth" via Jquery.ajax, so the API site settings are required to allow the "Auth" request header)
Access-control-allow-methods: Indicates that the site allows those request predicates (Get,post,options,put ...)

In the ASP. NET Web API, there are two ways to enable cross-domain access:
The first is to install the "Microsoft.AspNet.WebApi.Cors" package on NuGet and use the [Enablecors] feature for the API controller
The second type is configured in Web. config:

You must comment out "<remove name=" Optionsverbhandler "/>" To turn on the options verb processing, otherwise prefight will fail when cross-domain access.

The API code that returns sensitive information related to the user is as follows:

//marking the controller requires authentication[Apiauthorize] Public classUsercontroller:apicontroller { Public stringGet () {//Get back user information (in Apiauthorize by parsing token's payload and saving in Routedata)AuthInfo AuthInfo = This. requestcontext.routedata.values["Auth"] asAuthInfo; if(AuthInfo = =NULL)                return "Invalid acceptance Information"; Else                return string. Format ("hello: {0}, successful data acquisition", Authinfo.username); }    }

Front-end site

To this, the API site code is written to complete. Next, write the code for the front-end site.

The front-end site has only one HTML page and contains two simple features: invoking the Login interface to log on, and invoking an interface that is secured for authentication to obtain data

The key script code for the front-end page is as follows:

$(function () {            //Call the API site's login interface, and the interface returns a token after the login is successful. $ ("#login"). On ("click",function() {$.ajax ({URL:"Http://localhost:8056/api/login", Data: $ ("Form"). Serialize (), Method:"POST", Success:function(data) {if(data. Success) {//for simplicity, save the token in a global variable. Window.token =data.                            Token; Alert ("Login Successful"); } Else{alert ("Login failed:" +data.                        Message);            }                    }                });            }); //invokes an interface that obtains data from an API site that requires authentication. $ ("#invoke"). On ("click",function() {$.ajax ({URL:"Http://localhost:8056/api/user", Method:"Get", headers: {"Auth": Window.token},//sending tokens via the request header, discarding the way cookies are sentCompletefunction(jqxhr,textstatus) {alert (jqxhr.responsetext);            },                                    });        });    }); </script>

Next, call the interface to get the data without logging in and log in, and use Fiddler to monitor the request and response process.

Press "Invoke interface" directly without logging in, the server returns 401 unauthorized information

The following are the communication conditions:

This time first login, and then call the interface, also in the Fiddler to monitor the communication situation.

In fiddler, you can see that the entire process browser makes 3 requests, namely login, prefight before calling the interface, and the actual calling interface:

Take a look at each communication situation

Login process:

Prefight

Actually issue a GET request call interface to get the data

In this case, the demo for authentication and cross-domain access based on JWT has been completed, so please correct me if there is a mistake.

Demo Source

JWT-based Web API authentication and cross-domain invocation practices

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.