API 不要 return 当前用户。 returning 500 内部服务器错误
API don't return CurrentUser. returning 500 internal server error
Startup.cs 文件配置
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(options =>
{
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"));
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:3000");
});
});
services.AddMediatR(typeof(list.Handler).Assembly);
services.AddMvc(opt => {
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
opt.Filters.Add(new AuthorizeFilter(policy));
})
.AddFluentValidation(cfg => cfg.RegisterValidatorsFromAssemblyContaining<create>());
var builder = services.AddIdentityCore<AppUser>();
var identityBuilder = new IdentityBuilder(builder.UserType, builder.Services);
identityBuilder.AddEntityFrameworkStores<DataContext>();
identityBuilder.AddSignInManager<SignInManager<AppUser>>();
services.AddScoped<IJwtGenerator, JwtGenerator>();
services.AddScoped<IUserAccessor, UserAccessor>();
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["TokenKey"]));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(
opt => {
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = key,
ValidateAudience = false,
ValidateIssuer = false
};
}
);
}
我的 UserDefine 中间件
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ErrorHandlingMiddleware> _logger;
public ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger)
{
_logger = logger;
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex, _logger);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception ex,
ILogger<ErrorHandlingMiddleware> logger)
{
object errors = null;
switch(ex)
{
case RestException re:
logger.LogError(ex, "Rest Error");
errors = re.Errors;
context.Response.StatusCode = (int)re.Code;
break;
case Exception e:
logger.LogError(ex, "Server Error");
errors = string.IsNullOrWhiteSpace(e.Message) ? "Error" : e.Message;
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
context.Response.ContentType = "application/json";
if(errors != null)
{
var result = JsonConvert.SerializeObject(new {
errors
});
await context.Response.WriteAsync(result);
}
}
}
RestException 文件
public class RestException : Exception
{
public RestException(HttpStatusCode code, object errors = null)
{
Code = code;
Errors = errors;
}
public HttpStatusCode Code { get; }
public object Errors { get; }
}
UserAccessor 文件
public class UserAccessor : IUserAccessor
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string GetCurrentUsername()
{
var username = _httpContextAccessor.HttpContext.User?.Claims?.FirstOrDefault( x=> x.Type == ClaimTypes.NameIdentifier)?.Value;
return username;
}
}
这是我的当前用户文件 return 当前用户信息 API
public class CurrentUser
{
public class Query : IRequest<User> { }
public class Handler : IRequestHandler<Query, User>
{
private readonly IJwtGenerator _jwtGenerator;
private readonly IUserAccessor _userAccessor;
private readonly UserManager<AppUser> _userManager;
public Handler(UserManager<AppUser> userManager, IJwtGenerator jwtGenerator, IUserAccessor userAccessor)
{
_userAccessor = userAccessor;
_jwtGenerator = jwtGenerator;
_userManager = userManager;
}
public async Task<User> Handle(Query request, CancellationToken cancellationToken)
{
var user = await _userManager.FindByNameAsync(_userAccessor.GetCurrentUsername());
return new User
{
DisplayName = user.DisplayName,
Username = user.UserName,
Token = _jwtGenerator.CreateToken(user),
Image = null
};
}
}
}
我通过 POSTMAN 和服务器 returning 测试了这个并且 VsCode 显示了这些错误
500 Internal Server Error
fail: API.MiddleWare.ErrorHandlingMiddleware[0] Server Error System.ArgumentNullException: Value cannot be null. (Parameter 'userName') at Microsoft.AspNetCore.Identity.UserManager
1.FindByNameAsync(字符串用户名)
在 Application.Users.CurrentUser.Handler.Handle(查询请求,CancellationToken cancellationToken)
在 C:\Users\NOYON\source\repos\reactivity\Application\Users\CurrentUser.cs:第 28 行
在 MediatR.Pipeline.RequestExceptionProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestExceptionProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestExceptionActionProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestExceptionActionProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestPostProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestPreProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 API.Controllers.UserController.CurrentUser() 中 C:\Users\NOYON\source\repos\reactivity\api\Controllers\UserController.cs:第 28 行
在 lambda_method(闭包,对象)
在 Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
在 Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper 映射器,ObjectMethodExecutor
执行者、对象控制器、对象 [] 参数)
在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker 调用程序,ValueTask1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at API.MiddleWare.ErrorHandlingMiddleware.Invoke(HttpContext context) in C:\Users\NOYON\source\repos\reactivity\api\Middleware\ErrorHandlingMiddleware.cs:line 25
当我从 UserController 调用用户时 API 说
{"errors":"Value cannot be null. (Parameter 'userName')"}
为什么这个 GetCurrentUser() return 用户名为空?这不是获取当前用户的正确说明吗?
因为您没有 post 您的 Startup.cs
文件,所以我不知道您当前的 JWT 配置是什么。但是,如果您在 JWT 中使用 sub
属性 作为用户名,则应在下面添加此行
x.TokenValidationParameters = new TokenValidationParameters
{
...,
NameClaimType = ClaimTypes.NameIdentifier
};
如果想在JWT token中只获取一个key,可以通过以下代码获取
var handler = new JwtSecurityTokenHandler();
var jwtTokenStr = httpRequest.Headers["Authorization"].ToString().Replace("Bearer ", string.Empty, System.StringComparison.Ordinal);
var jwtToken = handler.ReadJwtToken(jwtTokenStr);
// Get Sub by this line
jwtToken.Claims.FirstOrDefault(a => a.Type == JwtClaimTypes.Subject)?.Value
GetCurrentUsername() 正确执行。尝试几次后,我想改变它的工作方式。虽然现在和我在这里声明的一样。我不知道为什么会这样。
Startup.cs 文件配置
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(options =>
{
options.UseSqlite(Configuration.GetConnectionString("DefaultConnection"));
});
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", policy =>
{
policy.AllowAnyHeader().AllowAnyMethod().WithOrigins("http://localhost:3000");
});
});
services.AddMediatR(typeof(list.Handler).Assembly);
services.AddMvc(opt => {
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
opt.Filters.Add(new AuthorizeFilter(policy));
})
.AddFluentValidation(cfg => cfg.RegisterValidatorsFromAssemblyContaining<create>());
var builder = services.AddIdentityCore<AppUser>();
var identityBuilder = new IdentityBuilder(builder.UserType, builder.Services);
identityBuilder.AddEntityFrameworkStores<DataContext>();
identityBuilder.AddSignInManager<SignInManager<AppUser>>();
services.AddScoped<IJwtGenerator, JwtGenerator>();
services.AddScoped<IUserAccessor, UserAccessor>();
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["TokenKey"]));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(
opt => {
opt.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = key,
ValidateAudience = false,
ValidateIssuer = false
};
}
);
}
我的 UserDefine 中间件
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ErrorHandlingMiddleware> _logger;
public ErrorHandlingMiddleware(RequestDelegate next, ILogger<ErrorHandlingMiddleware> logger)
{
_logger = logger;
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex, _logger);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception ex,
ILogger<ErrorHandlingMiddleware> logger)
{
object errors = null;
switch(ex)
{
case RestException re:
logger.LogError(ex, "Rest Error");
errors = re.Errors;
context.Response.StatusCode = (int)re.Code;
break;
case Exception e:
logger.LogError(ex, "Server Error");
errors = string.IsNullOrWhiteSpace(e.Message) ? "Error" : e.Message;
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
context.Response.ContentType = "application/json";
if(errors != null)
{
var result = JsonConvert.SerializeObject(new {
errors
});
await context.Response.WriteAsync(result);
}
}
}
RestException 文件
public class RestException : Exception
{
public RestException(HttpStatusCode code, object errors = null)
{
Code = code;
Errors = errors;
}
public HttpStatusCode Code { get; }
public object Errors { get; }
}
UserAccessor 文件
public class UserAccessor : IUserAccessor
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public string GetCurrentUsername()
{
var username = _httpContextAccessor.HttpContext.User?.Claims?.FirstOrDefault( x=> x.Type == ClaimTypes.NameIdentifier)?.Value;
return username;
}
}
这是我的当前用户文件 return 当前用户信息 API
public class CurrentUser
{
public class Query : IRequest<User> { }
public class Handler : IRequestHandler<Query, User>
{
private readonly IJwtGenerator _jwtGenerator;
private readonly IUserAccessor _userAccessor;
private readonly UserManager<AppUser> _userManager;
public Handler(UserManager<AppUser> userManager, IJwtGenerator jwtGenerator, IUserAccessor userAccessor)
{
_userAccessor = userAccessor;
_jwtGenerator = jwtGenerator;
_userManager = userManager;
}
public async Task<User> Handle(Query request, CancellationToken cancellationToken)
{
var user = await _userManager.FindByNameAsync(_userAccessor.GetCurrentUsername());
return new User
{
DisplayName = user.DisplayName,
Username = user.UserName,
Token = _jwtGenerator.CreateToken(user),
Image = null
};
}
}
}
我通过 POSTMAN 和服务器 returning 测试了这个并且 VsCode 显示了这些错误
500 Internal Server Error
fail: API.MiddleWare.ErrorHandlingMiddleware[0] Server Error System.ArgumentNullException: Value cannot be null. (Parameter 'userName') at Microsoft.AspNetCore.Identity.UserManager
1.FindByNameAsync(字符串用户名)
在 Application.Users.CurrentUser.Handler.Handle(查询请求,CancellationToken cancellationToken)
在 C:\Users\NOYON\source\repos\reactivity\Application\Users\CurrentUser.cs:第 28 行
在 MediatR.Pipeline.RequestExceptionProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestExceptionProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestExceptionActionProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestExceptionActionProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestPostProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 MediatR.Pipeline.RequestPreProcessorBehavior2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate
1 下一个)
在 API.Controllers.UserController.CurrentUser() 中 C:\Users\NOYON\source\repos\reactivity\api\Controllers\UserController.cs:第 28 行
在 lambda_method(闭包,对象)
在 Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
在 Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper 映射器,ObjectMethodExecutor
执行者、对象控制器、对象 [] 参数)
在 Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker 调用程序,ValueTask1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync() --- End of stack trace from previous location where exception was thrown --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) at API.MiddleWare.ErrorHandlingMiddleware.Invoke(HttpContext context) in C:\Users\NOYON\source\repos\reactivity\api\Middleware\ErrorHandlingMiddleware.cs:line 25
当我从 UserController 调用用户时 API 说
{"errors":"Value cannot be null. (Parameter 'userName')"}
为什么这个 GetCurrentUser() return 用户名为空?这不是获取当前用户的正确说明吗?
因为您没有 post 您的 Startup.cs
文件,所以我不知道您当前的 JWT 配置是什么。但是,如果您在 JWT 中使用 sub
属性 作为用户名,则应在下面添加此行
x.TokenValidationParameters = new TokenValidationParameters
{
...,
NameClaimType = ClaimTypes.NameIdentifier
};
如果想在JWT token中只获取一个key,可以通过以下代码获取
var handler = new JwtSecurityTokenHandler();
var jwtTokenStr = httpRequest.Headers["Authorization"].ToString().Replace("Bearer ", string.Empty, System.StringComparison.Ordinal);
var jwtToken = handler.ReadJwtToken(jwtTokenStr);
// Get Sub by this line
jwtToken.Claims.FirstOrDefault(a => a.Type == JwtClaimTypes.Subject)?.Value
GetCurrentUsername() 正确执行。尝试几次后,我想改变它的工作方式。虽然现在和我在这里声明的一样。我不知道为什么会这样。