In the previous blog post, we obtained ACC based on the ASP. OWIN OAuth with Resource Owner Password Credentials Grant (Grant_type=password). ESS token and, with this token, successfully invokes the Web API associated with the current user (resource owner).
I thought I'd done it. Access token has done the validation and authorization of the Web API, but found that there is a token in OAuth called Refresh token. At first it was very puzzling that access token was able to solve the problem, why do we have to take care of two sets of Token,refresh tokens? Under the puzzled, issued this feeling: the birth of access token, Mr He refresh token?
Later read some information, a little understand. Refresh token is a token that is dedicated to updating access tokens.
Why Refresh access tokens? First, because access token has an expiration time, the access token expires when the expiration date, it needs to be refreshed, and the second is because an access token associates certain user rights, and if the user authorizes the change, the access token needs to be refreshed to correlate The new permissions.
Why use a token to update access tokens? If there is no refresh token, you can also refresh access token, but each refresh will have to enter the user login username and password, more trouble. With refresh token, you can reduce the hassle, the client directly with refresh token to update access token, without the user to do extra work.
Two why might not explain the purpose of the refresh token, let's take a look at the example code in the ASP. NET Web API and OWIN OAuth, perhaps with a more intuitive understanding.
(a) The creation, distribution and preservation of the Refresh token
Implement a refreshtokenprovider, such as Cnblogsrefreshtokenprovider.
The Createasync () and Receiveasync () methods in Interface Microsoft.Owin.Security.Infrastructure.IAuthenticationTokenProvider () need to be implemented, The sample code is as follows:
Public classcnblogsrefreshtokenprovider:iauthenticationtokenprovider{Private Staticconcurrentdictionary<string, authenticationticket> _refreshtokens =Newconcurrentdictionary<string, authenticationticket>(); Public AsyncTask Createasync (Authenticationtokencreatecontext context) {varGUID =Guid.NewGuid (). ToString (); varRefreshtokenproperties =Newauthenticationproperties (context. Ticket.Properties.Dictionary) {ISSUEDUTC=context. TICKET.PROPERTIES.ISSUEDUTC, EXPIRESUTC= DateTime.UtcNow.AddYears (1) }; varRefreshtokenticket =NewAuthenticationticket (context. Ticket.identity, refreshtokenproperties); _refreshtokens.tryadd (GUID, refreshtokenticket); Context. Settoken (GUID); } Public AsyncTask Receiveasync (Authenticationtokenreceivecontext context) {Authenticationticket ticket; if(_refreshtokens.tryremove (context). Token, outticket)) {context. Setticket (ticket); } }}
Then apply this cnblogsrefreshtokenprovider:
Public voidConfigureauth (Iappbuilder app) {oauthoptions=Newoauthauthorizationserveroptions {Tokenendpointpath=NewPathString ("/token"), Provider=NewCnblogsauthorizationserverprovider (), Accesstokenexpiretimespan= Timespan.fromdays (1), Allowinsecurehttp=true, refreshtokenprovider = new Cnblogsrefreshtokenprovider () }; App. Useoauthbearertokens (oauthoptions);}
(ii) Verification of the client holding the refresh token
Overload the Oauthauthorizationserverprovider.grantrefreshtoken () method, the sample code is as follows:
usingMicrosoft.Owin.Security.OAuth;namespaceopenapi.providers{ Public classCnblogsauthorizationserverprovider:oauthauthorizationserverprovider { Public Override AsyncTask Grantrefreshtoken (Oauthgrantrefreshtokencontext context) {varOriginalclient = context. ticket.properties.dictionary["as:client_id"]; varCurrentclient = context. ClientId; if(Originalclient! =currentclient) {context. Rejected (); return; } varNewId =Newclaimsidentity (context. ticket.identity); Newid.addclaim (NewClaim ("Newclaim","Refreshtoken")); varNewticket =NewAuthenticationticket (newId, context. Ticket.properties); Context. Validated (Newticket); await Base. Grantrefreshtoken (context); } }}
In order to verify the client_id, you need to save the client_id to context in the grantclientcredentials () overloaded method. Ticket:
namespaceopenapi.providers{ Public classCnblogsauthorizationserverprovider:oauthauthorizationserverprovider { Public Override AsyncTask grantclientcredentials (Oauthgrantclientcredentialscontext context) {varOauthidentity =Newclaimsidentity (context. Options.authenticationtype); varProps =NewAuthenticationproperties (Newdictionary<string,string> { { "as:client_id", context. CLIENTID}}); varTicket =NewAuthenticationticket (oauthidentity, props); Context. Validated (ticket); } }}
Just implement the above code, and the rest is for you by Microsoft.Owin.Security.OAuth.
(iii) test client gets Refresh token
The client gets access token together with the refresh token, the sample code is as follows:
[Fact] Public AsyncTask getaccesstokentest () {varClientId ="[ClientId]"; varClientsecret ="[Clientsecret]"; varParameters =Newdictionary<string,string>(); Parameters. ADD ("Grant_type","Password"); Parameters. ADD ("username","[Username]"); Parameters. ADD ("Password","[Password]"); _httpclient.defaultrequestheaders.authorization=NewAuthenticationheadervalue ("Basic", Convert.tobase64string (Encoding.ASCII.GetBytes (clientId+":"+( Clientsecret))); varResponse =await_httpclient.postasync ("/token",Newformurlencodedcontent (parameters)); varResponsevalue =awaitResponse. Content.readasstringasync (); Console.WriteLine (Responsevalue);}
Operation Result:
{ "Access_token": "D3vjxsfvr ...", "Token_type": "Bearer", "expires_in": 86399, "Refresh_token ":" 449ba200-4232-4763-b868-8c27d7583dec "}
Successfully got access token.
(iv) test client refreshes access token with refresh token
The client test code is as follows:
Public AsyncTask getaccesstokentest () {varClientId ="[ClientId]"; varClientsecret ="[Clientsecret]"; varParameters =Newdictionary<string,string>(); Parameters. ADD ("Grant_type","Refresh_token"); Parameters. ADD ("Refresh_token","ec9f14b6-e25e-46c0-ad30-9aa0562b694c"); _httpclient.defaultrequestheaders.authorization=NewAuthenticationheadervalue ("Basic", Convert.tobase64string (Encoding.ASCII.GetBytes (clientId+":"+( Clientsecret))); varResponse =await_httpclient.postasync ("/token",Newformurlencodedcontent (parameters)); varResponsevalue =awaitResponse. Content.readasstringasync (); Console.WriteLine (Responsevalue);}
Note: The main difference between this client code and the client code in the previous step is that there is less code to pass the resource owner username and password below, which is where the refresh token is used--without requiring a username and password to refresh access token.
Parameters. ADD ("username""[username]");p arameters. ADD ("password""[password]");
Operation Result:
{ "Access_token": "[New access token]", " token_type": "Bearer", "expires_in": 86399, "Refresh_token ":" [New Refresh token] "}
Get!
It looks quite simple, but it's been a day of tossing. Hopefully, this blog post will help you reduce your time when you toss OAuth.
Resources
Adding Refresh Tokens to a Web API v2 Authorization Server
Embeddedresourceownerflowwithrefreshtokens
Web API and OAuth: Both access token, Mr He refresh token