时间:2021-07-01 10:21:17 帮助过:6人阅读
然后应用这个 CNBlogsRefreshTokenProvider:
public void ConfigureAuth(IAppBuilder app) { OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/token"), Provider = new CNBlogsAuthorizationServerProvider(), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), AllowInsecureHttp = true, RefreshTokenProvider = new CNBlogsRefreshTokenProvider() }; app.UseOAuthBearerTokens(OAuthOptions); }
(二)验证持有 refresh token 的客户端
重载 OAuthAuthorizationServerProvider.GrantRefreshToken() 方法,示例代码如下:
using Microsoft.Owin.Security.OAuth; namespace OpenAPI.Providers { public class CNBlogsAuthorizationServerProvider : OAuthAuthorizationServerProvider { public override async Task GrantRefreshToken(OAuthGrantRefreshTokenContext context) { var originalClient = context.Ticket.Properties.Dictionary["as:client_id"]; var currentClient = context.ClientId; if (originalClient != currentClient) { context.Rejected(); return; } var newId = new ClaimsIdentity(context.Ticket.Identity); newId.AddClaim(new Claim("newClaim", "refreshToken")); var newTicket = new AuthenticationTicket(newId, context.Ticket.Properties); context.Validated(newTicket); await base.GrantRefreshToken(context); } } }
为了验证client_id,需要在 GrantClientCredentials() 重载方法中保存client_id至context.Ticket:
namespace OpenAPI.Providers { public class CNBlogsAuthorizationServerProvider : OAuthAuthorizationServerProvider { public override async Task GrantClientCredentials(OAuthGrantClientCredentialsContext context) { var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType); var props = new AuthenticationProperties(new Dictionary<string, string> { { "as:client_id", context.ClientId } }); var ticket = new AuthenticationTicket(oAuthIdentity, props); context.Validated(ticket); } } }
只需实现上面这些代码,其他的都由 Microsoft.Owin.Security.OAuth 帮你代劳了。
(三)测试客户端获取 refresh token
客户端获取 access token 与 refresh token 是一起的,示例代码如下:
[Fact] public async Task GetAccessTokenTest() { var clientId = "[clientId]"; var clientSecret = "[clientSecret]"; var parameters = new Dictionary<string, string>(); parameters.Add("grant_type", "password"); parameters.Add("username", "[username]"); parameters.Add("password", "[password]"); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(clientId + ":" + clientSecret))); var response = await _httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters)); var responseValue = await response.Content.ReadAsStringAsync(); Console.WriteLine(responseValue); }
运行结果:
{ "access_token": "D3VjxsFvr...", "token_type": "bearer", "expires_in": 86399, "refresh_token": "449ba200-4232-4763-b868-8c27d7583dec" }
成功拿到了 access token。
(四)测试客户端用 refresh token 刷新 access token
客户端测试代码如下:
public async Task GetAccessTokenTest() { var clientId = "[clientId]"; var clientSecret = "[clientSecret]"; var parameters = new Dictionary<string, string>(); parameters.Add("grant_type", "refresh_token"); parameters.Add("refresh_token", "ec9f14b6-e25e-46c0-ad30-9aa0562b694c"); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(clientId + ":" + clientSecret))); var response = await _httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters)); var responseValue = await response.Content.ReadAsStringAsync(); Console.WriteLine(responseValue); }
注:这段客户端代码与前一步中客户端代码的主要区别是少了下面传递 resource owner 用户名与密码的代码,这就是 refresh token 的用途所在 —— 不需要用户名与密码就可以刷新 access token。
parameters.Add("username", "[username]"); parameters.Add("password", "[password]");
运行结果:
{ "access_token": "[new access token]", "token_type": "bearer", "expires_in": 86399, "refresh_token": "[new refresh token]" }
搞定!
看起来挺简单,却折腾了一天。 希望在你折腾OAuth的时候,这篇博文能够帮你减少折腾的时间。
【参考资料】
Adding Refresh Tokens to a Web API v2 Authorization Server
EmbeddedResourceOwnerFlowWithRefreshTokens
Web API与OAuth:既生access token,何生refresh token
标签: