JSON WEB TOKENS

Source: Internet
Author: User

In the previous blog, I wrote a middleware to deal with API authorization verification, now in another way to deal with the issue of authorization verification, after all, it is now

There are a lot of open source things to use, today is the JWT.

What is a JWT? The full name of the JWT is the JSON WEB TOKENS, which is a self-contained token format. Official website: https://jwt.io/, more or less should have heard this.

Let's take a look at the following two graphs:

Site is the way to access the API through RPC to obtain resources, when the site is directly access to the API, do not get access to the token, then the site is not to get the relevant data resources.

As shown in the diagram on the left, the request was initiated but not the desired result, and when the site first went to the authorization server to access the API's Access_token (token), the

Access_token access to API,API will not return the protected data resource.

This is the approximate process based on token verification. It can be seen that the authorization server occupies a very important position.

Let's take a look at what the authorization server does and how to implement a simple authorization.

What have you done? The role of the authorization server throughout the process is to receive the client to initiate a request for Access_token and verify the legitimacy of its identity, and eventually return a containing

The JSON string for the Access_token.

How is it implemented? We are still inseparable from the middleware of this thing. This time we wrote a tokenprovidermiddleware, mainly to look at the Invoke method and generate Access_token

The method.

1//         <summary> 2//         invoke the Middleware 3//         </summary> 4//         <param name= "context" & Gt;</param> 5         //<returns></returns> 6 public         Async Task Invoke (HttpContext context) 7         {            8             if (!context. Request.Path.Equals (_options. Path, StringComparison.Ordinal)) 9             {                 await _next (context);             }12             /Request must be POST with Content-type:application/x-www-form-urlencoded14             if (!context. Request.Method.Equals ("POST")                | |!context. Request.hasformcontenttype)                 (returnbadrequest) (context);             }19             await generateauthorizedresult (context);         

The Invoke method does not have to say much, but here we do a control, only receive the POST request, and is only to receive the data submitted in form form, get request and its

His contenttype type is an illegal request and will return the status of bad request.

Here is the more important thing in authorization, the generation of Access_token.

 1//<summary> 2//Get the JWT 3//</summary> 4//<param name= "user         Name "></param> 5//<returns></returns> 6 private string GETJWT (string username) 7                 {8 var now = Datetime.utcnow; 9 var claims = new Claim[]11 {12 New Claim (jwtregisteredclaimnames.sub, username), new Claim (JWTREGISTEREDCLAIMNAMES.JTI, Guid.newgui D (). ToString ()), Claim New (Jwtregisteredclaimnames.iat, now. ToUniversalTime (). ToString (), claimvaluetypes.integer64)-};17 var JWT = new Jwtsecu Ritytoken (issuer: _options. issuer,20 Audience: _options. audience,21 claims:claims,22 notbefore:now,23 Expires:now. ADD (_options. Expiration), Signingcredentials: _options. Signingcredentials); 25 var encodedjwt = new Jwtsecuritytokenhandler ().                 Writetoken (JWT); var response = new28 {Access_token = encodedjwt,30 expires_in = (int) _options.   expiration.totalseconds,31 Token_type = "Bearer" 32}; Jsonconvert.serializeobject return (response, new jsonserializersettings {formatting = formatting.indented }); 34}

Claims contains multiple claim, which you want to add to your needs, jwtregisteredclaimnames is a struct with all the options available.

Jwtregisteredclaimnames

A Jwtsecuritytoken object is also required, and this object is critical. With the time, claims, and Jwtsecuritytoken objects, just call Jwtsecuritytokenhandler

Writetoken can get an encrypted string like this, which is made up of 3 parts using '. ' Separated . Each section represents what can be found on the official website.

EyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBa B30rmhrhdcefxjoyzgefonfh7hgq

Finally, we'll return the Access_token, Access_token's effective time, and some other information in the form of JSON.

We also need to call our middleware in the Configure method of startup.

1             var audienceconfig = configuration.getsection ("Audience"); 2             var symmetricKeyAsBase64 = audienceconfig[" Secret "]; 3             var keybytearray = Encoding.ASCII.GetBytes (symmetricKeyAsBase64); 4             var signingkey = new Symmetricsecuritykey (Keybytearray); 5  6             apps. Usetokenprovider (New Tokenprovideroptions 7             {8                 audience = "Catcher Wong", 9                 Issuer = "/http/ catcher1994.cnblogs.com/",                 signingcredentials = new Signingcredentials (Signingkey, securityalgorithms.hmacsha256), one             });

Here, our authorized Service site is ready. Write a few unit tests below to verify this authorization.

Test one: The Authorized Service site can generate the correct JWT.

1         [Fact] 2 public         async Task authorized_server_should_generate_token_success () 3         {4             //arrange 5             var data = new dictionary<string, string> (); 6             data. ADD ("username", "Member"); 7             data. ADD ("password", "123"); 8             httpcontent ct = new formurlencodedcontent (data), 9             //act11             System.Net.Http.HttpResponseMessage Message_token = await _client. Postasync ("Http://127.0.0.1:8000/auth/token", CT);             string res = await Message_token. Content.readasstringasync ();             var obj = newtonsoft.json.jsonconvert.deserializeobject<token> (res); 14             //assert16             assert.notnull (obj),             assert.equal ("All", obj.expires_in);             assert.equal (3, Obj.access_token. Split ('. '). Length);             assert.equal ("Bearer", obj.token_type);         

Test Two: The Authorized Service site cannot generate the correct JWT because the user name or password is incorrect.

1         [Fact] 2 public         async Task Authorized_server_should_generate_token_fault_by_invalid_app () 3         {4             // Arrange 5             var data = new dictionary<string, string> (); 6             data. ADD ("username", "Member"); 7             data. ADD ("Password", "123456"); 8             httpcontent ct = new formurlencodedcontent (data), 9             //act11             System.Net.Http.HttpResponseMessage Message_token = await _client. Postasync ("Http://127.0.0.1:8000/auth/token", CT);             var res = await Message_token. Content.readasstringasync ();             Dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject (res);             Assert16             assert.equal ("Invalid_grant", (string) obj.error),             assert.equal (Httpstatuscode.badrequest, Message_token. StatusCode);         

Test Three: The Authorized Service site cannot generate the correct JWT because it is not initiating a POST request.

1         [Fact] 2 public         async Task Authorized_server_should_generate_token_fault_by_invalid_httpmethod () 3         {4             //arrange 5             Uri uri = new Uri ("http://127.0.0.1:8000/auth/token?username=Member&password=123456"); 6  7             //act 8             System.Net.Http.HttpResponseMessage Message_token = await _client. Getasync (URI); 9             var res = await Message_token. Content.readasstringasync ();             Dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject (res);             assert13             assert.equal ("Invalid_grant", (string) obj.error);             assert.equal (Httpstatuscode.badrequest, Message_token. StatusCode);         

Take a look at the results of the test: all passed.

Breakpoint take a access_token to http://jwt.calebb.net/decryption look

Eyjhbgcioijiuzi1niisinr5cci6ikpxvcj9.eyjzdwiioijnzw1izxiilcjqdgkioii2mzi1mme1my0ymjy5ltq4yzetymqwni1lowrimzdmmtrmytqilcjp Yxqioiiymde2lzexlzeyidi6ndg6mtcilcjuymyioje0nzg5mtg4otcsimv4cci6mtq3odkxotq5nywiaxnzijoiahr0cdovl2nhdgnozxixotk0lmnuymxvz 3muy29tlyisimf1zci6iknhdgnozxigv29uzyj9.cu2vtj4jahgbjgzwv2jcmvz17hcyosrntjktiea0ebq

The following is the development of the API.

This is a demonstration of the valuecontroller generated directly from the new API project, which is similar to the ASP. The point here is to configure

Jwtbearerauthentication, here is no need for us to write another middleware, we are defined to use the option and then directly with the jwtbearerauthentication can be.

 1 public void Configurejwtauth (Iapplicationbuilder app) 2 {3 var audienceconfig = Configuration.getsection ("Audience"); 4 var symmetricKeyAsBase64 = audienceconfig["Secret"]; 5 var Keybytearray = Encoding.ASCII.GetBytes (symmetricKeyAsBase64);             6 var signingkey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey (Keybytearray); 7 8 var tokenvalidationparameters = new Tokenvalidationparameters 9 {ten//the SI Gning key must match!11 Validateissuersigningkey = true,12 Issuersigningkey = signingkey,1 3//Validate the JWT Issuer (ISS) claim15 Validateissuer = true,16 Val                 Idissuer = "http://catcher1994.cnblogs.com/", +//Validate the JWT audience (AUD) claim19      Validateaudience = true,20 validaudience = "Catcher Wong", 21 22           Validate the token expiry23 validatelifetime = true,24 Clockskew = Timespan.zero26};27 app.                 Usejwtbearerauthentication (new JwtBearerOptions29 {automaticauthenticate = true,31             Automaticchallenge = true,32 Tokenvalidationparameters = tokenvalidationparameters,33                        }); 34}

Then call the above method in the startup configure.

1 public         void Configure (Iapplicationbuilder app, Ihostingenvironment env, iloggerfactory loggerfactory) 2         {3             Loggerfactory.addconsole (configuration.getsection ("Logging")); 4             loggerfactory.adddebug (); 5 6             Configurejwtauth (APP), 7 8             app. Usemvc (); 9         }

After this, most of the work is done, and the most important step is to add authorize to the API that you want to protect, so that the Get method will be

Ask for Access_token to return the result, otherwise it will return 401. This is done on a single method, or it can be added to the entire controller, so that the side of the controller is attribute

Law will be protected.

1         //Get API/VALUES/52         [HttpGet ("{ID}")]3         [authorize]4 public         string GET (int id) 5         {6             return "Value"; 7         }

OK, also write several unit tests to verify.

Test One: Valueapi returns a 401 status in the absence of an authorization request.

1         [Fact] 2 public         void Value_api_should_return_unauthorized_without_auth () 3         {            4             //act          5             Httpresponsemessage message = _client. Getasync ("HTTP://LOCALHOST:63324/API/VALUES/1"). Result; 6             String result = message. Content.readasstringasync (). Result; 7           8             //assert 9             assert.false (message. Issuccessstatuscode);             assert.equal (httpstatuscode.unauthorized,message. StatusCode);             assert.empty (result);         

  

Test two: Valueapi request a method without the [authorize] flag to return the result normally.

1         [Fact] 2 public         void Value_api_should_return_result_without_authorize_attribute () 3         {4             //act          5             Httpresponsemessage message = _client. Getasync ("Http://localhost:63324/api/values"). Result; 6             String result = message. Content.readasstringasync (). Result; 7             var res = newtonsoft.json.jsonconvert.deserializeobject<string[]> (result); 8  9             //assert10             assert.true (message. Issuccessstatuscode);             assert.equal (2, Res. Length);         

  

Test Three: Valueapi returns the correct result in an authorized request.

1         [Fact] 2 public         void Value_api_should_success_by_valid_auth () 3         {4             //arrange 5             var data = new Dictionary<string, string> (); 6             data. ADD ("username", "Member"); 7             data. ADD ("password", "123"); 8             httpcontent ct = new formurlencodedcontent (data), 9             //act11             var obj = getaccesstoken (CT);             _client. Defaultrequestheaders.add ("Authorization", "Bearer" + obj.access_token);             Httpresponsemessage message = _ Client. Getasync ("HTTP://LOCALHOST:63324/API/VALUES/1"). result;14             String result = message. Content.readasstringasync (). result;15             //assert17             assert.true (message. Issuccessstatuscode)             assert.equal (3, Obj.access_token. Split ('. '). Length);             assert.equal ("value", result);            (         }

Take a look at the results of the test:

  

Test passed.

The protected method is accessed directly through the browser. The response header will prompt Www-authenticate:bearer, which is an authentication challenge that tells the client that it must provide a

Access to this resource (API) should be authenticated.

This is the reason why a header is added to the unit test, and the normal use is to add this to the requested message header.

_client. Defaultrequestheaders.add ("Authorization", "Bearer" + obj.access_token);

Actually look at the source code, faster to know why. JwtBearerHandler.cs

is about the Head plus authorization source interpretation.

Jwtbearer Source: Microsoft.AspNetCore.Authentication.JwtBearer Sample code for this article: Jwttokendemo Thanks for your reading!!!

JSON WEB TOKENS

Related Article

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.