本篇介紹使用簡單的 Refresh Token 機制
預設的 Web API 專案中並沒有提供 Refresh Token 的範例。
網路上「OWIN Security - How to Implement OAuth2 Refresh Tokens」提供一個簡單的實作,
它是用透過 GUID 來當Key值,並將值存放在 ConcurrentDictionary<string, AuthenticationTicket> 之中。
拿「Web API bearer token 驗證」的範例,再加入 Refresh Token 的實作。
新增 SimpleRefreshTokenProvider 實作 IAuthenticationTokenProvider ,如下,
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
{
//實際放到DB去存起來
private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens =
new ConcurrentDictionary<string, AuthenticationTicket>();
public async Task CreateAsync(AuthenticationTokenCreateContext context)
{
var guid = Guid.NewGuid().ToString();
//copy properties and set the desired lifetime of refresh token
var refreshTokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary)
{
IssuedUtc = context.Ticket.Properties.IssuedUtc,
//時間是3個月
ExpiresUtc = DateTime.UtcNow.AddMonths(3)
};
var refreshTokenTicket = new AuthenticationTicket(context.Ticket.Identity, refreshTokenProperties);
_refreshTokens.TryAdd(guid, refreshTokenTicket);
context.SetToken(guid);
}
public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
{
AuthenticationTicket ticket;
if (_refreshTokens.TryRemove(context.Token, out ticket))
{
context.SetTicket(ticket);
}
}
public void Create(AuthenticationTokenCreateContext context)
{
throw new NotImplementedException();
}
public void Receive(AuthenticationTokenReceiveContext context)
{
throw new NotImplementedException();
}
}
然後在 App_Start\Startup.Auth.cs 中設定 OAuthOptions 裡的RefreshTokenProvider,如下,
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
RefreshTokenProvider = new SimpleRefreshTokenProvider(),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
Controllers裡的ValuesController.cs 可以多傳出 User 的資訊,如下,
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2", User.Identity.Name };
}
建置執行,然後就可以用 Fiddler 來測試它。
1.取得 Access Token 及 Refresh Token,如下,
使用 POST , Request Body如下,
grant_type=password&username=rainmaker&password=rainmaker
2.再用 Refresh Token 來取得新的 Access Token 及 Refresh Token,如下,
拿上面取得的 Refresh Token 再取得新的,grant_type則使用 refresh_token,
使用 POST , Request Body如下,
grant_type=refresh_token&refresh_token=cc1ce9fd-ede5-4d19-b2d1-626856ef5dd6
用過的 Refresh Token 會從 ConcurrentDictionary 移除,所以再執行 Step 2 會失敗,如下,
3.用 access_token 去取 ValuesController 的資料,如下,
使用 GET,URL為 http://localhost:51528/api/values
Header加入,Authorization:Bearer [access token]
參考資料
OWIN Security - How to Implement OAuth2 Refresh Tokens
Hi,
亂馬客Blog已移到了 「亂馬客 : Re:從零開始的軟體開發生活」
請大家繼續支持 ^_^