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

ABP Framework中移动端如何无需密码生成Access Token或授权码?

ABP 移动端/Blazor WASM 无密码短信验证码认证方案

核心思路

基于ABP集成的IdentityServer扩展自定义授权类型,让移动端、Blazor WASM通过标准OAuth2.0流程向IdentityServer请求Token,而非手动生成。所有Token由IdentityServer统一颁发,确保合法性与安全性。

1. 实现自定义短信验证码授权验证器

ABP的IdentityServer支持扩展授权类型,通过实现IExtensionGrantValidator接口完成短信验证码的验证逻辑:

步骤1:编写验证器

public class SmsCodeGrantValidator : IExtensionGrantValidator
{
    private readonly IIdentityUserRepository _userRepository;
    private readonly ISmsCodeVerificationService _smsCodeService; // 你已实现的短信验证码验证服务

    public string GrantType => "sms_code";

    public SmsCodeGrantValidator(IIdentityUserRepository userRepository, ISmsCodeVerificationService smsCodeService)
    {
        _userRepository = userRepository;
        _smsCodeService = smsCodeService;
    }

    public async Task ValidateAsync(ExtensionGrantValidationContext context)
    {
        var phoneNumber = context.Request.Raw["phone_number"];
        var smsCode = context.Request.Raw["sms_code"];

        // 验证参数完整性
        if (string.IsNullOrEmpty(phoneNumber) || string.IsNullOrEmpty(smsCode))
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "手机号或验证码不能为空");
            return;
        }

        // 验证短信验证码有效性
        var isValid = await _smsCodeService.VerifyCodeAsync(phoneNumber, smsCode);
        if (!isValid)
        {
            context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "验证码无效或已过期");
            return;
        }

        // 获取或自动注册用户(根据业务需求调整)
        var user = await _userRepository.FindByPhoneNumberAsync(phoneNumber);
        if (user == null)
        {
            user = await _userRepository.InsertAsync(new IdentityUser(Guid.NewGuid(), phoneNumber, phoneNumber));
        }

        // 返回验证成功结果
        context.Result = new GrantValidationResult(
            subject: user.Id.ToString(),
            authenticationMethod: GrantType,
            claims: new[] { new Claim("phone_number", phoneNumber) }
        );
    }
}

步骤2:注册验证器并配置授权类型

在你的ABP模块ConfigureServices方法中添加:

public override void ConfigureServices(ServiceConfigurationContext context)
{
    // 注册自定义授权验证器
    context.Services.AddTransient<IExtensionGrantValidator, SmsCodeGrantValidator>();

    // 允许自定义授权类型
    Configure<AbpIdentityServerOptions>(options =>
    {
        options.GrantTypes.Add("sms_code");
    });
}

2. 移动端调用流程

移动端(iOS/Android)直接与IdentityServer的Token端点交互:

  • 发送验证码:用户输入手机号后,APP调用后端短信发送接口(如/api/account/send-sms-code),后端生成验证码并存储(建议用Redis,设置5分钟过期),同时发送短信。
  • 请求Token:用户输入验证码后,向IdentityServer的/connect/token端点发起POST请求,参数如下:
    grant_type: sms_code
    client_id: 你的移动端客户端ID(需在ABP IdentityServer客户端配置中创建)
    phone_number: 用户输入的手机号
    sms_code: 用户输入的验证码
    
    注:移动端属于公开客户端,无需传client_secret,需在客户端配置中设置ClientType为Public。
  • 使用Token:验证通过后,IdentityServer返回access_token、refresh_token等参数,APP存储Token后,后续调用API时在请求头携带Authorization: Bearer {access_token}。

3. Blazor WebAssembly调用流程

Blazor WASM作为前端应用,流程与移动端类似:

  • 发送验证码:在登录组件中,用户输入手机号后调用后端短信发送接口。
  • 请求Token:用户输入验证码后,通过HttpClient向/connect/token端点发送POST请求,参数同移动端。
  • 更新认证状态:拿到Token后,调用ABP的AuthManager.LoginAsync方法传入Token,更新应用认证状态,后续API调用会自动携带Token。

示例代码(Blazor WASM):

public async Task LoginWithSmsCode(string phoneNumber, string smsCode)
{
    var tokenResponse = await HttpClient.PostAsync("/connect/token", new FormUrlEncodedContent(new Dictionary<string, string>
    {
        ["grant_type"] = "sms_code",
        ["client_id"] = "YourBlazorClientId",
        ["phone_number"] = phoneNumber,
        ["sms_code"] = smsCode
    }));

    if (tokenResponse.IsSuccessStatusCode)
    {
        var tokenResult = await tokenResponse.Content.ReadFromJsonAsync<TokenResponse>();
        await AuthManager.LoginAsync(new AuthTokenProvider(tokenResult.AccessToken, tokenResult.RefreshToken));
        NavigationManager.NavigateTo("/");
    }
    else
    {
        // 处理错误提示
    }
}

4. 关键配置与安全注意事项

  • 客户端配置:在ABP后台IdentityServer客户端管理中创建对应客户端,需设置:
    • AllowedGrantTypes包含sms_code
    • AllowedScopes包含需访问的API Scope(如DefaultApi)
    • 移动端/WASM客户端设为Public类型,无需客户端密钥
  • 验证码安全:限制短信发送频率(如1分钟内仅允许发送一次),验证码使用6位随机数字,存储时设置5分钟过期
  • 用户逻辑:根据业务需求决定是否自动注册手机号用户,或仅允许已注册用户登录

内容的提问来源于stack exchange,提问作者Omer Faruk KAYA

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 10:13:29