[英]How to get Refresh token by calling Authorization endpoint on Identity server 4
[英]Identity Server 4 - saving refresh token in datatabase
我正在.Net Core 2.0中使用IdentityServer4,並且已成功生成訪問令牌和刷新令牌。 我只需要能夠在服務器端“刷新”令牌生成時就可以看到它,以便出於某些特定目的將其保存在數據庫中。
在服務器上生成刷新令牌時,如何訪問它的值?
根據評論,我認為這對您和其他您的案件將是一個有用的解決方案。
我從圍繞IdentityServer本身的事情開始。 由於強烈建議在生產環境中使用您自己的PersistedGrant
存儲,因此我們需要覆蓋默認存儲。
首先-在Startup.cs中:
services.AddTransient<IPersistedGrantStore, PersistedGrantStore>();
這將使用我們自己的PersistedGrantStore
類實現其IPersistedGrantStore
接口。
類本身:
public class PersistedGrantStore : IPersistedGrantStore
{
private readonly ILogger logger;
private readonly IPersistedGrantService persistedGrantService;
public PersistedGrantStore(IPersistedGrantService persistedGrantService, ILogger<PersistedGrantStore> logger)
{
this.logger = logger;
this.persistedGrantService = persistedGrantService;
}
public Task StoreAsync(PersistedGrant token)
{
var existing = this.persistedGrantService.Get(token.Key);
try
{
if (existing == null)
{
logger.LogDebug("{persistedGrantKey} not found in database", token.Key);
var persistedGrant = token.ToEntity();
this.persistedGrantService.Add(persistedGrant);
}
else
{
logger.LogDebug("{persistedGrantKey} found in database", token.Key);
token.UpdateEntity(existing);
this.persistedGrantService.Update(existing);
}
}
catch (DbUpdateConcurrencyException ex)
{
logger.LogWarning("exception updating {persistedGrantKey} persisted grant in database: {error}", token.Key, ex.Message);
}
return Task.FromResult(0);
}
public Task<PersistedGrant> GetAsync(string key)
{
var persistedGrant = this.persistedGrantService.Get(key);
var model = persistedGrant?.ToModel();
logger.LogDebug("{persistedGrantKey} found in database: {persistedGrantKeyFound}", key, model != null);
return Task.FromResult(model);
}
public Task<IEnumerable<PersistedGrant>> GetAllAsync(string subjectId)
{
var persistedGrants = this.persistedGrantService.GetAll(subjectId).ToList();
var model = persistedGrants.Select(x => x.ToModel());
logger.LogDebug("{persistedGrantCount} persisted grants found for {subjectId}", persistedGrants.Count, subjectId);
return Task.FromResult(model);
}
public Task RemoveAsync(string key)
{
var persistedGrant = this.persistedGrantService.Get(key);
if (persistedGrant != null)
{
logger.LogDebug("removing {persistedGrantKey} persisted grant from database", key);
try
{
this.persistedGrantService.Remove(persistedGrant);
}
catch (DbUpdateConcurrencyException ex)
{
logger.LogInformation("exception removing {persistedGrantKey} persisted grant from database: {error}", key, ex.Message);
}
}
else
{
logger.LogDebug("no {persistedGrantKey} persisted grant found in database", key);
}
return Task.FromResult(0);
}
public Task RemoveAllAsync(string subjectId, string clientId)
{
var persistedGrants = this.persistedGrantService.GetAll(subjectId, clientId);
logger.LogDebug("removing {persistedGrantCount} persisted grants from database for subject {subjectId}, clientId {clientId}", persistedGrants.Count(), subjectId, clientId);
try
{
this.persistedGrantService.RemoveAll(persistedGrants);
}
catch (DbUpdateConcurrencyException ex)
{
logger.LogInformation("removing {persistedGrantCount} persisted grants from database for subject {subjectId}, clientId {clientId}: {error}", persistedGrants.Count(), subjectId, clientId, ex.Message);
}
return Task.FromResult(0);
}
public Task RemoveAllAsync(string subjectId, string clientId, string type)
{
var persistedGrants = this.persistedGrantService.GetAll(subjectId, clientId, type);
logger.LogDebug("removing {persistedGrantCount} persisted grants from database for subject {subjectId}, clientId {clientId}, grantType {persistedGrantType}", persistedGrants.Count(), subjectId, clientId, type);
try
{
this.persistedGrantService.RemoveAll(persistedGrants);
}
catch (DbUpdateConcurrencyException ex)
{
logger.LogInformation("exception removing {persistedGrantCount} persisted grants from database for subject {subjectId}, clientId {clientId}, grantType {persistedGrantType}: {error}", persistedGrants.Count(), subjectId, clientId, type, ex.Message);
}
return Task.FromResult(0);
}
}
如您所見,我有一個界面和記錄器。
IPersistedGrantService
接口:
public interface IPersistedGrantService
{
void Add(PersistedGrantInfo persistedGrant);
void Update(PersistedGrantInfo existing);
PersistedGrantInfo Get(string key);
IEnumerable<PersistedGrantInfo> GetAll(string subjectId);
IEnumerable<PersistedGrantInfo> GetAll(string subjectId, string clientId);
IEnumerable<PersistedGrantInfo> GetAll(string subjectId, string clientId, string type);
void Remove(PersistedGrantInfo persistedGrant);
void RemoveAll(IEnumerable<PersistedGrantInfo> persistedGrants);
}
如您所見,存在一個名為PersistedGrantInfo
的對象。 這是我的DTO,用於在db實體和IDS4實體之間進行映射(您不必強制使用它,但我正在這樣做是為了獲得更好的抽象性)。
此信息對象通過AutoMapper映射到IDS4實體:
public static class PersistedGrantMappers
{
internal static IMapper Mapper { get; }
static PersistedGrantMappers()
{
Mapper = new MapperConfiguration(cfg => cfg.AddProfile<PersistedGrantMapperProfile>())
.CreateMapper();
}
/// <summary>
/// Maps an entity to a model.
/// </summary>
/// <param name="entity">The entity.</param>
/// <returns></returns>
public static PersistedGrant ToModel(this PersistedGrantInfo entity)
{
return entity == null ? null : Mapper.Map<PersistedGrant>(entity);
}
/// <summary>
/// Maps a model to an entity.
/// </summary>
/// <param name="model">The model.</param>
/// <returns></returns>
public static PersistedGrantInfo ToEntity(this PersistedGrant model)
{
return model == null ? null : Mapper.Map<PersistedGrantInfo>(model);
}
/// <summary>
/// Updates an entity from a model.
/// </summary>
/// <param name="model">The model.</param>
/// <param name="entity">The entity.</param>
public static void UpdateEntity(this PersistedGrant model, PersistedGrantInfo entity)
{
Mapper.Map(model, entity);
}
}
以及映射器配置文件:
public class PersistedGrantMapperProfile:Profile
{
/// <summary>
/// <see cref="PersistedGrantMapperProfile">
/// </see>
/// </summary>
public PersistedGrantMapperProfile()
{
CreateMap<PersistedGrantInfo, IdentityServer4.Models.PersistedGrant>(MemberList.Destination)
.ReverseMap();
}
}
回到IPersistedGrantService
實現由您決定。 當前作為數據庫實體,我具有IDS4實體的精確副本:
public class PersistedGrant
{
[Key]
public string Key { get; set; }
public string Type { get; set; }
public string SubjectId { get; set; }
public string ClientId { get; set; }
public DateTime CreationTime { get; set; }
public DateTime? Expiration { get; set; }
public string Data { get; set; }
}
但是根據您的需要,您可以做一些不同的事情(將此數據存儲在不同的表中,使用不同的列名等)。 然后在我的服務實現中,我只是使用來自IPersistedGrantStore實現中的數據,並對數據庫上下文中的實體進行CRUD處理。
得出結論-這里的主要任務是根據您的需要覆蓋/實現其IPersistedGrantStore
接口。 希望這會有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.