使用Owin Middleware实现是否可以在执行Web API控制器之前添加声明?
创建了一个OwinMiddleware实现并添加了一个标识:
var id = new ClaimsIdentity();
id.AddClaim(new Claim("Whatever", "is possible"));
context.Authentication.User.AddIdentity(id);
await Next.Invoke(context);
但是,即使这个调用方法调用,身份也不会更新(只是内部声明数组)。并且控制器在执行时当然永远不会得到新的假声明。
想法?
答案 0 :(得分:1)
您可能会发现有用的继承自Authorizate Attribute并将其扩展以满足您的要求:
public class DemoAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext){
if (Authorize(actionContext)){
return;
}
HandleUnauthorizedRequest(actionContext);
}
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext){
var challengeMessage = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized;
//Adding your code here
var id = new ClaimsIdentity();
id.AddClaim(new Claim("Whatever", "is possible"));
context.Authentication.User.AddIdentity(id);
challengeMessage.Headers.Add("WWW-Authenticate", "Basic");
throw new HttpResponseException(challengeMessage);
}
private bool Authorize(System.Web.Http.Controllers.HttpActionContext actionContext){
try{
var someCode = (from h in actionContext.Request.Headers where h.Key == "demo" select h.Value.First()).FirstOrDefault();
// or check for the claims identity property.
return someCode == "myCode";
}
catch (Exception){
return false;
}
}
}
在你的控制器中:
[DemoAuthorize]
public class ValuesController : ApiController{
以下是WebApi授权的其他自定义实现的链接:
http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-membership-provider/
答案 1 :(得分:1)
已经有一个类可以提供声明丰富的ClaimsAuthenticationManager,您可以扩展它以处理特定于域的声明,例如......
public class MyClaimsAuthenticationManager : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (!incomingPrincipal.Identity.IsAuthenticated)
{
return base.Authenticate(resourceName, incomingPrincipal);
}
return AddApplicationClaims(incomingPrincipal);
}
private ClaimsPrincipal AddApplicationClaims(ClaimsPrincipal principal)
{
// TODO: Add custom claims here based on current principal.
return principal;
}
}
接下来的任务是提供适当的中间件来调用它。对于我的项目,我写了以下课程......
/// <summary>
/// Middleware component to apply claims transformation to current context
/// </summary>
public class ClaimsTransformationMiddleware
{
private readonly Func<IDictionary<string, object>, Task> next;
private readonly IServiceProvider serviceProvider;
public ClaimsTransformationMiddleware(Func<IDictionary<string, object>, Task> next, IServiceProvider serviceProvider)
{
this.next = next;
this.serviceProvider = serviceProvider;
}
public async Task Invoke(IDictionary<string, object> env)
{
// Use Katana's OWIN abstractions
var context = new OwinContext(env);
if (context.Authentication != null && context.Authentication.User != null)
{
var manager = serviceProvider.GetService<ClaimsAuthenticationManager>();
context.Authentication.User = manager.Authenticate(context.Request.Uri.AbsoluteUri, context.Authentication.User);
}
await next(env);
}
}
然后是布线扩展...
public static class AppBuilderExtensions
{
/// <summary>
/// Add claims transformation using <see cref="ClaimsTransformationMiddleware" /> any depdendency resolution is done via IoC
/// </summary>
/// <param name="app"></param>
/// <param name="serviceProvider"></param>
/// <returns></returns>
public static IAppBuilder UseClaimsTransformation(this IAppBuilder app, IServiceProvider serviceProvider)
{
app.Use<ClaimsTransformationMiddleware>(serviceProvider);
return app;
}
}
我知道这是服务定位器反模式,但使用IServiceProvider是容器中立的,似乎是将依赖项放入Owin中间件的可接受方式。
最后你需要在你的Startup中连接它,下面的例子假定Unity并注册/公开一个IServiceLocator属性......
// Owin config
app.UseClaimsTransformation(UnityConfig.ServiceLocator);
答案 2 :(得分:0)
这是我最终在owin中间件中添加新声明的方式,基于OP关于挂钩到UseOAuthBearerAuthentication的评论。它使用IdentityServer3.AccessTokenValidation,它在内部调用UseOAuthBearerAuthentication并将OAuthBearerAuthenticationProvider传递给它。
using System.Security.Claims;
using System.Threading.Tasks;
using IdentityServer3.AccessTokenValidation;
using Owin;
using Microsoft.Owin.Security.OAuth;
//...
public void Configuration(IAppBuilder app)
{
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "http://127.0.0.1/identityserver",
TokenProvider = new OAuthBearerAuthenticationProvider
{
OnValidateIdentity = AddClaim
}
});
}
private Task AddClaim(OAuthValidateIdentityContext context)
{
context.Ticket.Identity.AddClaim(new Claim("test", "123"));
return Task.CompletedTask;
}