IClaimsTransofrmer updated to take ClaimsTransformationContext instead of ClaimsPrincipal in TransformAsync method. #718

This commit is contained in:
Dovydas Navickas 2016-03-06 01:48:08 +02:00 committed by Hao Kung
parent 4bfeba2a3c
commit f5c1c45db2
8 changed files with 47 additions and 21 deletions

View File

@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Builder
/// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param> /// <param name="app">The <see cref="IApplicationBuilder"/> to add the middleware to.</param>
/// <param name="transform">A function that asynchronously transforms one <see cref="ClaimsPrincipal"/> to another.</param> /// <param name="transform">A function that asynchronously transforms one <see cref="ClaimsPrincipal"/> to another.</param>
/// <returns>A reference to this instance after the operation has completed.</returns> /// <returns>A reference to this instance after the operation has completed.</returns>
public static IApplicationBuilder UseClaimsTransformation(this IApplicationBuilder app, Func<ClaimsPrincipal, Task<ClaimsPrincipal>> transform) public static IApplicationBuilder UseClaimsTransformation(this IApplicationBuilder app, Func<ClaimsTransformationContext, Task<ClaimsPrincipal>> transform)
{ {
if (app == null) if (app == null)
{ {
@ -46,12 +46,12 @@ namespace Microsoft.AspNetCore.Builder
throw new ArgumentNullException(nameof(transform)); throw new ArgumentNullException(nameof(transform));
} }
return app.UseClaimsTransformation(new ClaimsTransformationOptions return app.UseClaimsTransformation(new ClaimsTransformationOptions
{ {
Transformer = new ClaimsTransformer { OnTransform = transform } Transformer = new ClaimsTransformer { OnTransform = transform }
}); });
} }
/// <summary> /// <summary>
/// Adds the <see cref="ClaimsTransformationMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables claims transformation capabilities. /// Adds the <see cref="ClaimsTransformationMiddleware"/> middleware to the specified <see cref="IApplicationBuilder"/>, which enables claims transformation capabilities.
/// </summary> /// </summary>

View File

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
namespace Microsoft.AspNetCore.Authentication
{
public class ClaimsTransformationContext
{
public ClaimsTransformationContext(HttpContext context)
{
Context = context;
}
public HttpContext Context { get; }
public ClaimsPrincipal Principal { get; set; }
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features.Authentication; using Microsoft.AspNetCore.Http.Features.Authentication;
namespace Microsoft.AspNetCore.Authentication namespace Microsoft.AspNetCore.Authentication
@ -12,10 +13,12 @@ namespace Microsoft.AspNetCore.Authentication
public class ClaimsTransformationHandler : IAuthenticationHandler public class ClaimsTransformationHandler : IAuthenticationHandler
{ {
private readonly IClaimsTransformer _transform; private readonly IClaimsTransformer _transform;
private readonly HttpContext _httpContext;
public ClaimsTransformationHandler(IClaimsTransformer transform) public ClaimsTransformationHandler(IClaimsTransformer transform, HttpContext httpContext)
{ {
_transform = transform; _transform = transform;
_httpContext = httpContext;
} }
public IAuthenticationHandler PriorHandler { get; set; } public IAuthenticationHandler PriorHandler { get; set; }
@ -27,8 +30,12 @@ namespace Microsoft.AspNetCore.Authentication
await PriorHandler.AuthenticateAsync(context); await PriorHandler.AuthenticateAsync(context);
if (_transform != null && context?.Principal != null) if (_transform != null && context?.Principal != null)
{ {
var transformationContext = new ClaimsTransformationContext(_httpContext)
{
Principal = context.Principal
};
context.Authenticated( context.Authenticated(
await _transform.TransformAsync(context.Principal), await _transform.TransformAsync(transformationContext),
context.Properties, context.Properties,
context.Description); context.Description);
} }

View File

@ -35,13 +35,17 @@ namespace Microsoft.AspNetCore.Authentication
public async Task Invoke(HttpContext context) public async Task Invoke(HttpContext context)
{ {
var handler = new ClaimsTransformationHandler(Options.Transformer); var handler = new ClaimsTransformationHandler(Options.Transformer, context);
handler.RegisterAuthenticationHandler(context.GetAuthentication()); handler.RegisterAuthenticationHandler(context.GetAuthentication());
try try
{ {
if (Options.Transformer != null) if (Options.Transformer != null)
{ {
context.User = await Options.Transformer.TransformAsync(context.User); var transformationContext = new ClaimsTransformationContext(context)
{
Principal = context.User
};
context.User = await Options.Transformer.TransformAsync(transformationContext);
} }
await _next(context); await _next(context);
} }

View File

@ -9,11 +9,11 @@ namespace Microsoft.AspNetCore.Authentication
{ {
public class ClaimsTransformer : IClaimsTransformer public class ClaimsTransformer : IClaimsTransformer
{ {
public Func<ClaimsPrincipal, Task<ClaimsPrincipal>> OnTransform { get; set; } public Func<ClaimsTransformationContext, Task<ClaimsPrincipal>> OnTransform { get; set; }
public virtual Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) public virtual Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
{ {
return OnTransform?.Invoke(principal) ?? Task.FromResult(principal); return OnTransform?.Invoke(context) ?? Task.FromResult(context.Principal);
} }
} }
} }

View File

@ -14,8 +14,8 @@ namespace Microsoft.AspNetCore.Authentication
/// <summary> /// <summary>
/// Provides a central transformation point to change the specified principal. /// Provides a central transformation point to change the specified principal.
/// </summary> /// </summary>
/// <param name="principal">The principal to transform.</param> /// <param name="context"><see cref="ClaimsTransformationContext"/> containing principal to transform and current HttpContext.</param>
/// <returns>The transformed principal.</returns> /// <returns>The transformed principal.</returns>
Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal); Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context);
} }
} }

View File

@ -293,16 +293,16 @@ namespace Microsoft.AspNetCore.Authentication.Cookies
{ {
Transformer = new ClaimsTransformer Transformer = new ClaimsTransformer
{ {
OnTransform = p => OnTransform = context =>
{ {
if (!p.Identities.Any(i => i.AuthenticationType == "xform")) if (!context.Principal.Identities.Any(i => i.AuthenticationType == "xform"))
{ {
// REVIEW: Xform runs twice, once on Authenticate, and then once from the middleware // REVIEW: Xform runs twice, once on Authenticate, and then once from the middleware
var id = new ClaimsIdentity("xform"); var id = new ClaimsIdentity("xform");
id.AddClaim(new Claim("xform", "yup")); id.AddClaim(new Claim("xform", "yup"));
p.AddIdentity(id); context.Principal.AddIdentity(id);
} }
return Task.FromResult(p); return Task.FromResult(context.Principal);
} }
} }
}); });

View File

@ -222,7 +222,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
ClientId = "Test Id", ClientId = "Test Id",
ClientSecret = "Test Secret" ClientSecret = "Test Secret"
}, },
async context => async context =>
{ {
var req = context.Request; var req = context.Request;
var res = context.Response; var res = context.Response;
@ -273,7 +273,7 @@ namespace Microsoft.AspNetCore.Authentication.Google
{ {
var transaction = await sendTask; var transaction = await sendTask;
Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode); Assert.Equal(HttpStatusCode.Redirect, transaction.Response.StatusCode);
Assert.Equal("/error?FailureMessage=OMG"+UrlEncoder.Default.Encode(";Description=SoBad;Uri=foobar"), transaction.Response.Headers.GetValues("Location").First()); Assert.Equal("/error?FailureMessage=OMG" + UrlEncoder.Default.Encode(";Description=SoBad;Uri=foobar"), transaction.Response.Headers.GetValues("Location").First());
} }
else else
{ {
@ -774,12 +774,12 @@ namespace Microsoft.AspNetCore.Authentication.Google
AutomaticAuthenticate = true AutomaticAuthenticate = true
}); });
app.UseGoogleAuthentication(options); app.UseGoogleAuthentication(options);
app.UseClaimsTransformation(p => app.UseClaimsTransformation(context =>
{ {
var id = new ClaimsIdentity("xform"); var id = new ClaimsIdentity("xform");
id.AddClaim(new Claim("xform", "yup")); id.AddClaim(new Claim("xform", "yup"));
p.AddIdentity(id); context.Principal.AddIdentity(id);
return Task.FromResult(p); return Task.FromResult(context.Principal);
}); });
app.Use(async (context, next) => app.Use(async (context, next) =>
{ {