You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Duende Identity Server(IdentityServer4)用用户账号密码获取Token

问题:使用注册用户的用户名和密码直接获取Duende Identity Server Token

我已研究Duende Identity Server(IdentityServer4)数日,了解Scopes、Resources、Client等概念及用法。目前对客户端部分存在困惑:我已将AspIdentity的ApplicationUser集成到IdentityServer(配置代码如下),但调用Duende预定义的/connect/token端点时需提供ClientId和Secret,而我希望使用注册用户的用户名和密码来获取Token。我曾考虑创建自定义端点,通过SignInManager验证用户凭据后找到用户对应的客户端再登录,但这种需要再次向同一服务发起HTTP请求的方式较为不便,希望能找到更便捷的解决办法。

当前配置代码

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

builder.Services.AddSwaggerGen();

builder.Services
    .AddIdentityServer(options =>
    {
        options.Events.RaiseErrorEvents = true;
        options.Events.RaiseInformationEvents = true;
        options.Events.RaiseFailureEvents = true;
        options.Events.RaiseSuccessEvents = true;
        options.EmitStaticAudienceClaim = true;
    })
    .AddAspNetIdentity<ApplicationUser>()
    .AddConfigurationStore(options =>
    {
        options.ConfigureDbContext = b =>
            b.UseSqlite(connectionString, dbOpts => dbOpts.MigrationsAssembly(typeof(Program).Assembly.FullName));
    })
    .AddOperationalStore(options =>
    {
        options.ConfigureDbContext = b =>
            b.UseSqlite(connectionString, dbOpts => dbOpts.MigrationsAssembly(typeof(Program).Assembly.FullName));

        options.EnableTokenCleanup = true;
        options.RemoveConsumedTokens = true;
    });

builder.Services.AddAuthentication();

解决方案:使用Resource Owner Password Credentials Grant(ROPC流)

Duende Identity Server已经内置了支持用户名密码直接获取Token的授权流,不需要自定义端点,只需调整客户端配置并按规范调用/connect/token即可。

1. 配置支持ROPC流的客户端

在IdentityServer的客户端配置中,将AllowedGrantTypes设置为GrantTypes.ResourceOwnerPassword,并根据客户端类型调整是否需要ClientSecret:

  • 可信客户端(如后端服务、桌面应用):保留ClientSecrets并设置RequireClientSecret = true
  • 公开客户端(如SPA、移动应用):设置RequireClientSecret = false(无需传ClientSecret)

示例客户端配置(内存方式,实际建议用数据库配置)

builder.Services.AddIdentityServer()
    // ... 已有的其他配置(AddAspNetIdentity、AddConfigurationStore等)
    .AddInMemoryClients(new List<Client>
    {
        new Client
        {
            ClientId = "your-app-client",
            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
            // 可信客户端需配置Secret,公开客户端可移除这行并设RequireClientSecret=false
            ClientSecrets = { new Secret("your-client-secret".Sha256()) },
            RequireClientSecret = true,
            // 配置允许请求的Scope
            AllowedScopes = { "openid", "profile", "your-api-resource-scope" },
            // 允许获取Refresh Token(可选)
            AllowOfflineAccess = true,
            // 设置Token有效期(可选)
            AccessTokenLifetime = 3600
        }
    });

2. 调用/connect/token端点获取Token

直接向/connect/token发起POST请求,传入以下参数:

参数名说明
grant_type固定为password
username注册用户的用户名
password注册用户的密码
client_id配置的客户端ID
client_secret客户端Secret(仅可信客户端需要)
scope需要请求的Scope(如openid profile your-api-scope,多个用空格分隔)

curl请求示例

curl -X POST "https://your-identity-server-domain/connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&username=your-user&password=your-pass&client_id=your-app-client&client_secret=your-client-secret&scope=openid profile your-api-resource-scope"

3. 关键说明

  • 集成AspNetIdentity后,IdentityServer会自动使用SignInManager验证用户凭据,无需手动处理
  • ROPC流适用于信任度较高的场景(如内部应用、桌面客户端),不建议用于SPA或公共网页应用(存在用户名密码泄露风险),这类场景优先使用Authorization Code Flow with PKCE
  • 若使用数据库存储客户端配置,直接在数据库的Clients表中更新对应客户端的AllowedGrantTypes字段为password即可

内容的提问来源于stack exchange,提问作者Ravaei

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 05:35:50