我正在开发 IdentityServer4 应用程序。由于添加到 context.IssuedClaims 的声明值,生成的 Access_token 长度变得太长。我尝试删除称为“实体”的声明类型,它有助于减少 access_token 长度。但它也从 ClaimsPrincipal 中删除了索赔。有没有办法可以将此声明添加回我的 ClaimsPrincipal 中,以便我可以从所有客户端应用程序访问它?目前,我每次都会调用一个单独的 API 来取回索赔。下面是我的 ProfileService 中的代码,我在其中过滤声明。
public async Task GetProfileDataAsync(IdentityServer4.Models.ProfileDataRequestContext context)
{
var user = await _userManager.GetUserAsync(context.Subject);
var principal = await _claimsFactory.CreateAsync(user);
//Retrieve all the claims associated with the user
var claims = from claimsdata in principal.Claims select new System.Security.Claims.Claim(claimsdata.Type, claimsdata.Value);
//Exclude claim type "entity" since its huge in numbers and causing access_token size to grow
var claimsWithoutEntity = claims.Where(x => x.Type != "entity");
context.IssuedClaims.AddRange(claimsWithoutEntity);
var roleClaims = _roleService.GetRoleClaims(user);
context.IssuedClaims.AddRange(roleClaims);
}
在不修改访问令牌的情况下减少 cookie 大小的另一种替代方法是创建 SessionStore,您可以在此处使用 SessionStore 参数设置它:
}).AddCookie(options =>
{
...
options.SessionStore = new MySessionStore();
})
SessionStore 有什么作用?
这是内存存储示例
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Serilog;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
namespace SessionStore
{
/// <summary>
/// MySessionStore
///
/// Custom session store, to hold the tokens in memory instead of storing them inside the Cookie.
///
/// This provides an abstract storage mechanic to preserve identity information on the server while
/// only sending a simple identifier key to the client. This is most commonly used to mitigate issues
/// with serializing large identities into cookies.
///
/// TODO:
/// - Needs logic to remove older items, otherwise we might run out of memory here.
/// - Use the MemoryCache instead of a dictionary?
///
/// Written by Tore Nestenius to be used in the IdentityServer in production training class.
/// https://www.tn-data.se
///
/// </summary>
internal class MySessionStore : ITicketStore
{
private readonly Serilog.ILogger _logger;
private readonly ConcurrentDictionary<string, AuthenticationTicket> mytickets = new();
public MySessionStore()
{
_logger = Log.Logger;
}
/// <summary>
/// Remove the identity associated with the given key.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task RemoveAsync(string key)
{
_logger.Debug("MySessionStore.RemoveAsync Key=" + key);
if (mytickets.ContainsKey(key))
{
mytickets.TryRemove(key, out _);
}
return Task.FromResult(0);
}
/// <summary>
/// Tells the store that the given identity should be updated.
/// </summary>
/// <param name="key"></param>
/// <param name="ticket"></param>
/// <returns></returns>
public Task RenewAsync(string key, AuthenticationTicket ticket)
{
_logger.Debug("MySessionStore.RenewAsync Key=" + key + ", ticket = " + ticket.AuthenticationScheme);
mytickets[key] = ticket;
return Task.FromResult(false);
}
/// <summary>
/// Retrieves an identity from the store for the given key.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public Task<AuthenticationTicket> RetrieveAsync(string key)
{
_logger.Error("MySessionStore.RetrieveAsync Key=" + key);
if (mytickets.ContainsKey(key))
{
var ticket = mytickets[key];
return Task.FromResult(ticket);
}
else
{
return Task.FromResult((AuthenticationTicket)null!);
}
}
/// <summary>
/// Store the identity ticket and return the associated key.
/// </summary>
/// <param name="ticket"></param>
/// <returns></returns>
public Task<string> StoreAsync(AuthenticationTicket ticket)
{
//Only add one at the time to avoid race conditions
lock(this)
{
//Make sure the key is does not already exist in the dictionary
bool result = false;
string key;
do
{
key = Guid.NewGuid().ToString();
result = mytickets.TryAdd(key, ticket);
} while (result == false);
string username = ticket?.Principal?.Identity?.Name ?? "Unknown";
_logger.Debug("MySessionStore.StoreAsync ticket=" + username + ", key=" + key);
return Task.FromResult(key);
}
}
}
}
我确实写了一篇博文,更多地讨论了会话存储的目的以及它如何提高安全性: 通过减少 Cookie 来提高 ASP.NET Core 安全性