c# - 如何使用密码授予流程更改 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 身份的资源所有者密码流,因此没有针对登录用户的自定义用户服务。那么如何根据登录过程中发生的情况显示错误消息?
解决方案
这对我来说是这样的:
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>();
推荐阅读
- c# - 如何配置 Json 序列化程序,以允许 Azure Functions (V2) 中的循环引用?
- html - 将列表显示为表格行+在每行之前将内容作为表格单元格插入 - 如何跳过将内容添加到第一个 Li?
- c# - C# - 如何在不显式调用属性名称的情况下将属性值分配给对象
- c++ - CMake 找不到静态增强库
- python - Visual Studio Code for Python 中的编程文档字符串
- swift - 无法构建 Objective-C 模块 'Firebase' - swift
- java - GridBagLayout 上的摆动替换组件
- javascript - 如何定义要调用的函数:function1().function2()?
- kubernetes - Helm install, Kubernetes - 如何等待 Pod 准备好?
- python - python使用for循环创建层次结构