API不返回CurrentUser。返回500内部服务器错误

时间:2020-06-23 04:18:26

标签: asp.net-core asp.net-web-api asp.net-identity

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;
    }
}

这是我的CurrentUser文件,该文件将CurrentUser信息返回给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进行了测试,服务器返回And 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(String userName) 在Application.Users.CurrentUser.Handler.Handle(查询请求,CancellationToken cancelledToken) 在C:\ Users \ NOYON \ source \ repos \ reactivity \ Application \ Users \ CurrentUser.cs:第28行 在MediatR.Pipeline.RequestExceptionProcessorBehavior 2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate 1下) 在MediatR.Pipeline.RequestExceptionProcessorBehavior 2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate 1下) 在MediatR.Pipeline.RequestExceptionActionProcessorBehavior 2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate 1下) 在MediatR.Pipeline.RequestExceptionActionProcessorBehavior 2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate 1下) 在MediatR.Pipeline.RequestPostProcessorBehavior 2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate 1下) 在MediatR.Pipeline.RequestPreProcessorBehavior 2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate 1下) 在C. \ Users \ NOYON \ source \ repos \ reactivity \ api \ Controllers \ UserController.cs:第28行的API.Controllers.UserController.CurrentUser()中 在lambda_method(Closure,Object) 在Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult() 在Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper映射器,ObjectMethodExecutor 执行程序,对象控制器,Object []参数) 在Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited | 12_0(ControllerActionInvoker调用程序,ValueTask 1 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()返回用户名为null?这不是获取当前用户的正确指令吗?

2 个答案:

答案 0 :(得分:0)

因为您没有发布Startup.cs文件,所以我不知道您当前的JWT配置是什么。但是,如果您将JWT中的sub属性用作用户名,则应在下面添加此行

x.TokenValidationParameters = new TokenValidationParameters
{
     ...,
     NameClaimType = ClaimTypes.NameIdentifier
};

如果您想获得JWT令牌中的一个密钥,可以通过以下代码获取

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

答案 1 :(得分:0)

GetCurrentUsername()实现正确。经过几次尝试后,可以根据需要更改其工作方式。尽管现在和我在这里声明的一样。我不知道为什么会这样。