Jon*_*n H 4 c# asp.net-mvc claims-based-identity jwt asp.net-web-api
我有一个体系结构,在该体系结构中,我有一个初始的ASP MVC登陆页面,该页面调用Web API服务,而Web API服务又调用另外2个自身也具有的功能。
当前,身份验证是通过Windows身份验证用户user / roles处理的。
我想在到达aspmvc方面时获得身份服务器令牌(仍然使用Windows身份验证),然后返回带有适当声明/范围的令牌,可以通过提取并沿行将其用于所有后续调用。
这可能吗?什么是首选或最佳做法?也许我会使用服务器到服务器流来实现每一次飞跃..但是似乎又要获得另一个令牌..我什至会将它们放在内部玩偶中?
更新 - 与Matt G讨论后,我在回答中添加了更好的解释,以使我的观点更加清楚。我认为一开始我还不够清楚。
更新2 - 加点5
我认为应该为一个客户端颁发令牌,并且只有该特定客户端才能使用令牌来访问它要求访问的所有资源。
案件
评论
这意味着Api2可以访问Api3,Api4,Api5。但是,如果不应授予Api2访问权限,会发生什么?现在您遇到了问题。一旦出现这种情况,您就必须重新设计安全机制。
另外,这意味着发送到Api2的令牌包含与其无关的范围,这对我来说听起来有点奇怪。
另一方面,Api1的范围可能意味着与Api2不同,这可能导致误解。但这将取决于您的开发。
如果使用Scopes 进行身份验证和授权,则不应共享令牌,因为Api1可以执行例如Api2不应执行的代码,这是一个安全问题。
如果Api1是向IdP请求令牌的人。如果要与Api1分开使用,Api2会怎样?因为Api1没有将令牌传递给它,所以无法对其他Apis进行呼叫?还是所有的Apis都有能力向IdP请求令牌,并且所有的Apis都将令牌传递给其他Apis,具体取决于首次呼叫的是哪个Api?您是否可能提出了比需要更多的复杂性?
您试图实现的目标是可行的,但对我而言,这不是一个好主意。
下面我为您提出了解决此问题的替代解决方案。
听起来您每次需要执行HttpClient.Send时都需要TokenCache和一种将其注入的机制。这就是我建议你的。
您应该创建一个名为TokenCache的类,该类负责在每次过期,无效或为null时获取Token。
public class TokenCache : ITokenCache
{
public TokenClient TokenClient { get; set; }
private readonly string _scope;
private DateTime _tokenCreation;
private TokenResponse _tokenResponse;
public TokenCache(string scope)
{
_scope = scope;
}
private bool IsTokenValid()
{
return _tokenResponse != null &&
!_tokenResponse.IsError &&
!string.IsNullOrWhiteSpace(_tokenResponse.AccessToken) &&
(_tokenCreation.AddSeconds(_tokenResponse.ExpiresIn) > DateTime.UtcNow);
}
private async Task RequestToken()
{
_tokenResponse = await TokenClient.RequestClientCredentialsAsync(_scope).ConfigureAwait(false);
_tokenCreation = DateTime.UtcNow;
}
public async Task<string> GetAccessToken(bool forceRefresh = false)
{
if (!forceRefresh && IsTokenValid()) return _tokenResponse.AccessToken;
await RequestToken().ConfigureAwait(false);
if (!IsTokenValid())
{
throw new InvalidOperationException("An unexpected token validation error has occured during a token request.");
}
return _tokenResponse.AccessToken;
}
}
Run Code Online (Sandbox Code Playgroud)
您将创建一个类TokenHttpHandler,如下所示。每次执行HttpClient.Send时,此类将设置Bearer令牌。请注意,我们正在使用TokenCache(_tokenCache.GetAccessToken)在SetAuthHeaderAndSendAsync方法中获取令牌。这样,您可以确定每次从api / mvc应用程序调用另一个api时都会发送令牌。
public class TokenHttpHandler : DelegatingHandler
{
private readonly ITokenCache _tokenCache;
public TokenHttpHandler(ITokenCache tokenCache)
{
InnerHandler = new HttpClientHandler();
_tokenCache = tokenCache;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = await SetAuthHeaderAndSendAsync(request, cancellationToken, false).ConfigureAwait(false);
//check for 401 and retry
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
response = await SetAuthHeaderAndSendAsync(request, cancellationToken, true);
}
return response;
}
private async Task<HttpResponseMessage> SetAuthHeaderAndSendAsync(HttpRequestMessage request, CancellationToken cancellationToken, bool forceTokenRefresh)
{
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await _tokenCache.GetAccessToken(forceTokenRefresh).ConfigureAwait(false));
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
Run Code Online (Sandbox Code Playgroud)
然后,在ExtendedHttpClient中使用它,如下所示。注意,我们正在将TokenHttpHandler注入构造函数。
public class ExtendedHttpClient : HttpClient
{
public ExtendedHttpClient(TokenHttpHandler messageHandler) : base(messageHandler)
{
DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
}
}
Run Code Online (Sandbox Code Playgroud)
最后,在IoC配置中,您需要添加新的类。
如果要对多个MVC应用程序/ Api重用以上代码,则应将其放在共享库(例如基础结构)中,然后仅为每个IdentityServer客户端配置IoC。
builder.RegisterType<TokenHttpHandler>().AsSelf();
builder.RegisterType<ExtendedHttpClient>().As<HttpClient>();
builder.RegisterType<TokenCache>()
.As<ITokenCache>()
.WithParameter("scope", "YOUR_SCOPES")
.OnActivating(e => e.Instance.TokenClient = e.Context.Resolve<TokenClient>())
.SingleInstance();
builder.Register(context =>
{
var address = "YOUR_AUTHORITY";
return new TokenClient(address, "ClientID", "Secret");
})
.AsSelf();
Run Code Online (Sandbox Code Playgroud)
注意,此示例使用ClientCredentials流,但是您可以采用此概念并对其进行修改以使其符合您的要求。
希望能帮助到你。亲切的问候丹尼尔
这是微服务架构中非常常见的问题,通过API网关模式来处理。所有令牌验证都应在 API 网关级别处理。令牌验证后,请求应转发到(微)服务,该服务可以信任该请求。如果您需要更新/修复/改进/添加有关令牌安全性的任何内容,都可以在一个地方完成。
归档时间: |
|
查看次数: |
4922 次 |
最近记录: |