ASP.NET OWIN OAuth:遇到的2個refresh token問題

來源:互聯網
上載者:User

標籤:

之前寫過2篇關於refresh token的產生與持久化的博文:1)Web API與OAuth:既生access token,何生refresh token;2)ASP.NET OWIN OAuth:refresh token的持久化。

之後我們在CNBlogsRefreshTokenProvider中這樣實現了refresh token的產生與持久化:

public class CNBlogsRefreshTokenProvider : AuthenticationTokenProvider{    private IRefreshTokenService _refreshTokenService;    public CNBlogsRefreshTokenProvider(IRefreshTokenService refreshTokenService)    {        _refreshTokenService = refreshTokenService;    }    public override async Task CreateAsync(AuthenticationTokenCreateContext context)    {        if (string.IsNullOrEmpty(context.Ticket.Identity.Name)) return;        var clientId = context.OwinContext.Get<string>("as:client_id");        if (string.IsNullOrEmpty(clientId)) return;        var refreshTokenLifeTime = context.OwinContext.Get<string>("as:clientRefreshTokenLifeTime");        if (string.IsNullOrEmpty(refreshTokenLifeTime)) return;        //generate access token        RandomNumberGenerator cryptoRandomDataGenerator = new RNGCryptoServiceProvider();        byte[] buffer = new byte[60];        cryptoRandomDataGenerator.GetBytes(buffer);        var refreshTokenId = Convert.ToBase64String(buffer).TrimEnd(‘=‘).Replace(‘+‘, ‘-‘).Replace(‘/‘, ‘_‘);        var refreshToken = new RefreshToken()        {            Id = refreshTokenId,            ClientId = new Guid(clientId),            UserName = context.Ticket.Identity.Name,            IssuedUtc = DateTime.UtcNow,            ExpiresUtc = DateTime.UtcNow.AddSeconds(Convert.ToDouble(refreshTokenLifeTime)),            ProtectedTicket = context.SerializeTicket(),            IP = context.Request.GetUserIp()        };        context.Ticket.Properties.IssuedUtc = refreshToken.IssuedUtc;        context.Ticket.Properties.ExpiresUtc = refreshToken.ExpiresUtc;        if (await _refreshTokenService.Save(refreshToken))        {            context.SetToken(refreshTokenId);        }    }    public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context)    {        var refreshToken = await _refreshTokenService.Get(context.Token);        if (refreshToken != null)        {            context.DeserializeTicket(refreshToken.ProtectedTicket);            var result = await _refreshTokenService.Remove(context.Token);        }    }}
CNBlogsRefreshTokenProvider

後來發現一個問題(這是遇到的第1個問題),在使用者不登入的情況下,以client credentials grant方式擷取access token時,也會產生refresh token並且儲存至資料庫。而refresh token是為瞭解決以resource owner password credentials grant方式擷取access token時多次輸入使用者名稱與密碼的麻煩。所以,對於client credentials grant的情境,產生refresh token完全沒有必要。

於是,就得想辦法避免這種refresh token生不逢時的情況。後來,找到瞭解決方法,很簡單,只需在CreateAsync的重載方法的開頭加上如下的代碼:

public class CNBlogsRefreshTokenProvider : AuthenticationTokenProvider{    public override async Task CreateAsync(AuthenticationTokenCreateContext context)    {        if (string.IsNullOrEmpty(context.Ticket.Identity.Name)) return;        //...    }}

遇到的第2個問題是,Client多次以resource owner password credentials grant的方式擷取refresh token,會產生多個refresh token,並且會在資料庫中儲存多條記錄。

通常情況的操作是,Client以resource owner password credentials grant的方式擷取refresh token,並之將儲存。需要更新access token時就用這個refresh token去更新,更新的同時會產生新的refresh token,並且將原先的refresh token刪除。對應的實現代碼如下:

public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context){    var refreshToken = await _refreshTokenService.Get(context.Token);    if (refreshToken != null)    {        context.DeserializeTicket(refreshToken.ProtectedTicket);        var result = await _refreshTokenService.Remove(context.Token);    }}

但是當Client多次擷取多個refresh token時,只有那個用於重新整理access token的refresh token會被刪除,其他的refresh token會成為無人問津的垃圾留在資料庫中。為了愛護環境,不亂扔垃圾,我們得解決這個問題。

解決的思路是在產生新的refresh token並將之儲存至資料庫之前,將對應於這個使用者(resource owner)及這個client的所有refresh token刪除。刪除所依據的條件是ClientId與UserId,由於之前持久化refresh token時只儲存了UserName,沒有儲存UserId,所以要給RefreshToken增加UserId屬性。然後給Application層的IRefreshTokenService介面增加刪除方法:

public interface IRefreshTokenService{    //...    Task<bool> Remove(Guid clientId, Guid userId);}

(該方法的實現省略)

接著在CNBlogsRefreshTokenProvider中儲存refresh token之前,調用這個方法:

public class CNBlogsRefreshTokenProvider : AuthenticationTokenProvider{    private IRefreshTokenService _refreshTokenService;    public override async Task CreateAsync(AuthenticationTokenCreateContext context)    {            var refreshToken = new RefreshToken()        {            //...            UserId = (await UCenterService.GetUser(context.Ticket.Identity.Name)).UserID,            //...        };                    await _refreshTokenService.Remove(refreshToken.ClientId, refreshToken.UserId);        if (await _refreshTokenService.Save(refreshToken))        {            context.SetToken(refreshTokenId);        }    }}

這樣就解決了第2個問題。 

ASP.NET OWIN OAuth:遇到的2個refresh token問題

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.