首页 > 解决方案 > 如何使用密码授予流程更改 IdentityServer4 的默认错误消息

问题描述

将 IdentityServer4 与资源所有者密码流和 asp.net 身份一起使用时,登录失败时总是返回相同的错误消息。密码无效或用户已被锁定都没有关系。

{
    "error": "invalid_grant",
    "error_description": "invalid_username_or_password"
}

这是身份和身份服务器的配置:

services.AddIdentityCore<User>()
    .AddEntityFrameworkStores<ApplicationDBContext>()
    .AddDefaultTokenProviders()
    .AddUserManager<UserManager<User>>()
    .AddSignInManager<ApplicationSignInManager>();

var builder = services.AddIdentityServer()
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiResources(Config.Apis)
    .AddInMemoryClients(Config.Clients)
    .AddAspNetIdentity<User>();

由于我正在使用带有 asp.net 身份的资源所有者密码流,因此没有针对登录用户的自定义用户服务。那么如何根据登录过程中发生的情况显示错误消息?

标签: c#asp.net-coreasp.net-identityidentityserver4

解决方案


这对我来说是这样的:

using IdentityServer4.Models;
using IdentityServer4.Validation;
using Microsoft.AspNetCore.Identity;

public class CustomResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
    private readonly CustomUserRepository _repository;

    public CustomResourceOwnerPasswordValidator(CustomUserRepository repository)
    {
        _repository = repository;
    }

    // https://docs.identityserver.io/en/latest/topics/resource_owner.html
    public async System.Threading.Tasks.Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
    {
        var user = await _repository.FindUser(context.UserName, context.Password);
        if (user != null)
        {
            var passwordHasher = new PasswordHasher();
            var result = passwordHasher.VerifyHashedPassword(user.User.Password, context.Password);
            // https://docs.identityserver.io/en/latest/reference/grant_validation_result.html#refgrantvalidationresult
            if (result)
            {
                context.Result = new GrantValidationResult(subject: user.Id, authenticationMethod: "password");
            }
            else
            {
                context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid password");
            }
        }
        else
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid user");
        }
    }
}

这是在 Startup.cs 时这样注册的:

        var builder = services
            .AddIdentityServer()
            .AddSigningCredential(certificate)
            .AddInMemoryIdentityResources(Resources.Get())
            .AddInMemoryClients(Clients.Get(baseUri))
            .AddValidationKey(certificate)
            .AddProfileService<ProfileService>();
            .AddResourceOwnerValidator<CustomResourceOwnerPasswordValidator>();

对我来说,要让它工作,我需要在注册步骤结束时包括在内。.AddAspNetIdentity<User>();


推荐阅读