Reputation: 5238
I have base
class for every request in my app:
public abstract class BaseDto
{
public string Uid { get; set; }
}
public class RequestDto : BaseDto
{
public string SomeData { get; set; }
}
Im using my ReuqestDto
class in my controller actions:
[HttpGet]
public IEnumerable<string> Get(RequestDto req)
{
// some logic on request
if (req.Uid != null)
{
// perform action
}
}
The user passing only SomeData
property to me. In my JWT Token i have saved some information about Uid
for BaseDto
. What is the best way to write data to Uid
using middleware/filter to have that information in my Get()
method? I Tried to serialized HttpContext.Request.Body
but not success because i cant find, how to do it properly. Or maybe there are better solutions for this problem? How to write data to my incoming objects in app?
Upvotes: 0
Views: 914
Reputation: 961
I often created a filter which implements Attribute and IAsyncActionFilter to get the information before go inside the Controller's action.
Here is an example,
using System.IdentityModel.Tokens.Jwt;
public class UserProfileFilter : Attribute, IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
string uid = string.Empty;
StringValues authHeaderVal = default(StringValues);
// Get UID from JWT
if (context.HttpContext.Request.Headers.TryGetValue("Authorization", out authHeaderVal))
{
string bearerTokenPrefix = "Bearer";
string accessToken = string.Empty;
string authHeaderStr = authHeaderVal.ToString();
if (!string.IsNullOrEmpty(authHeaderStr) && authHeaderStr.StartsWith(bearerTokenPrefix, StringComparison.OrdinalIgnoreCase))
{
accessToken = authHeaderStr.Replace(bearerTokenPrefix, string.Empty, StringComparison.OrdinalIgnoreCase).Trim();
}
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadJwtToken(accessToken);
uid = token.Claims.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value;
}
// Or Get UID from ActionExecutingContext
var user = context.HttpContext.User;
if (user.Identity.IsAuthenticated)
{
uid = user.Claims.FirstOrDefault(c => c.Type.Equals("sub", StringComparison.OrdinalIgnoreCase))?.Value;
}
// Get payload
RequestDto payload = (RequestDto)context.ActionArguments?.Values.FirstOrDefault(v => v is RequestDto);
payload.Uid = uid;
await next();
}
}
And then you can put the filter on any action.
[HttpPost]
[Authorize]
[TypeFilter(typeof(UserProfileFilter))]
public ActionResult<IActionResult> AdminGet(RequestDto request)
{
Debug.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(request));
return this.Ok();
}
The above filter will use the sub
claim's value to overwrite the value of the incoming payload.
For example, if I post the payload as following,
{
"uid" : "",
"someData": "Test"
}
The action will finally output {"Uid":"MyID","SomeData":"Test"}
.
Upvotes: 1
Reputation: 2788
This is probably what you want.
You should to create own interface for models like that
public interface IMyRequestType { }
Your model should implement it for finding model in FilterAttribute
public class MyModel : IMyRequestType
{
public string ID { get; set; }
}
And create your filter attribute with OnActionExecuting
implentation
public class MyFilterAttribute : TypeFilterAttribute
{
public MyFilterAttribute() : base(typeof(MyFilterImpl)) { }
private class MyFilterImpl : IActionFilter
{
private readonly ILogger _logger;
public MyFilterAttributeImpl(ILoggerFactory loggerFactory)
{
// get something from DI
_logger = loggerFactory.CreateLogger<MyFilterAttributeImpl>();
}
public void OnActionExecuting(ActionExecutingContext context)
{
// get your request model
var model = context.ActionArguments.Values.OfType<IMyRequestType>().Single();
// get your key
//context.HttpContext.User or whatever
// do something with model
}
public void OnActionExecuted(ActionExecutedContext context)
{
// perform some logic work
}
}
}
Upvotes: 1