C
C#13mo ago
h

✅ Endpoint returns 400 when I add authorization code, works correctly without

Here is the authorization code:
public class UpdateUserAuthorizationHandler : AuthorizationHandler<UpdateUserRequirement>
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserService _userService;
private readonly IMapper _mapper;

public UpdateUserAuthorizationHandler(IHttpContextAccessor httpContextAccessor, UserService userService, IMapper mapper)
{
_httpContextAccessor = httpContextAccessor;
_userService = userService;
_mapper = mapper;
}

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, UpdateUserRequirement requirement)
{
if (!context.User.Identity.IsAuthenticated)
{
throw new InvalidTokenException("access");
}

var userId = int.Parse(context.User.Claims.First(c => c.Type == "id").Value);

var httpContext = _httpContextAccessor.HttpContext;
var bodyData = string.Empty;
using (var reader = new StreamReader(httpContext.Request.Body, Encoding.UTF8))
{
bodyData = await reader.ReadToEndAsync();
}
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
var userDto = JsonSerializer.Deserialize<UserDTO>(bodyData, options);
var targetUser = await _userService.GetUserById(userDto.Id);

if (targetUser != null && targetUser.Id == userId)
{
context.Succeed(requirement);
}
else
{
throw new UnauthorizedActionException(userId);
}
}
}
public class UpdateUserAuthorizationHandler : AuthorizationHandler<UpdateUserRequirement>
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserService _userService;
private readonly IMapper _mapper;

public UpdateUserAuthorizationHandler(IHttpContextAccessor httpContextAccessor, UserService userService, IMapper mapper)
{
_httpContextAccessor = httpContextAccessor;
_userService = userService;
_mapper = mapper;
}

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, UpdateUserRequirement requirement)
{
if (!context.User.Identity.IsAuthenticated)
{
throw new InvalidTokenException("access");
}

var userId = int.Parse(context.User.Claims.First(c => c.Type == "id").Value);

var httpContext = _httpContextAccessor.HttpContext;
var bodyData = string.Empty;
using (var reader = new StreamReader(httpContext.Request.Body, Encoding.UTF8))
{
bodyData = await reader.ReadToEndAsync();
}
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};
var userDto = JsonSerializer.Deserialize<UserDTO>(bodyData, options);
var targetUser = await _userService.GetUserById(userDto.Id);

if (targetUser != null && targetUser.Id == userId)
{
context.Succeed(requirement);
}
else
{
throw new UnauthorizedActionException(userId);
}
}
}
9 Replies
h
h13mo ago
Here is the failing controller:
/// <summary>
/// Update user
/// </summary>
[HttpPut]
[Authorize(Policy = "UpdateUserPolicy")]
public async Task<IActionResult> Put([FromBody] UserDTO user)
{
await _userService.UpdateUser(user);
return NoContent();
}
/// <summary>
/// Update user
/// </summary>
[HttpPut]
[Authorize(Policy = "UpdateUserPolicy")]
public async Task<IActionResult> Put([FromBody] UserDTO user)
{
await _userService.UpdateUser(user);
return NoContent();
}
The request I am giving to the controller:
{
"id": 22,
"avatar": "https://i.gyazo.com/image.jpg",
"email": "email@email.com",
"userName": "abc"
}
{
"id": 22,
"avatar": "https://i.gyazo.com/image.jpg",
"email": "email@email.com",
"userName": "abc"
}
Error:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-8cf778e26725b04bcee8ca370880e523-c5bc015a9dbf7254-00",
"errors": {
"$": [
"The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0."
]
}
}
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-8cf778e26725b04bcee8ca370880e523-c5bc015a9dbf7254-00",
"errors": {
"$": [
"The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0."
]
}
}
Expected response is 204 No Content and the user getting updated
Sossenbinder
Sossenbinder13mo ago
Did you debug the authorization code ahead of the json deserializer?
h
h13mo ago
yes, it works
Wz
Wz13mo ago
You consumed the stream, so the controller has an empty body to read
Sossenbinder
Sossenbinder13mo ago
Oh, indeed!
h
h13mo ago
thanks, but how do i write the stream back? or do i have to use a different method of retrieving the body?
Sossenbinder
Sossenbinder13mo ago
You need to use requestbuffering
Sossenbinder
Sossenbinder13mo ago
Jeremy Caney
.NET Blog
Re-reading ASP.Net Core request bodies with EnableBuffering() - .NE...
This post describes the EnableBuffering() extension method which enable re-reading of ASP.NET Core request body.
Accord
Accord12mo ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.