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

在托管Blazor WebAssembly中为登录/注册配置不同Azure AD B2C用户流

配置独立的Azure AD B2C登录与注册用户流

一、客户端配置调整

1. 更新appsettings.json

将原合一流配置替换为包含两个独立策略的配置:

"AzureAdB2C": {
  "Instance": "https://***.b2clogin.com/",
  "Domain": "***.onmicrosoft.com",
  "ClientId": "****",
  "ValidateAuthority": false,
  "SignInPolicyId": "B2C_1_SIGN_IN",
  "SignUpPolicyId": "B2C_1_SIGN_UP"
}

2. 改造登录/注册触发逻辑

在LoginDisplay.razor中拆分登录和注册操作,指定对应策略:

<AuthorizeView>
    <Authorized>
        Hello, @context.User.Identity.Name!
        <button class="nav-link btn btn-link" @onclick="Logout">Log out</button>
    </Authorized>
    <NotAuthorized>
        <button class="nav-link btn btn-link" @onclick="Login">Log in</button>
        <button class="nav-link btn btn-link" @onclick="SignUp">Sign up</button>
    </NotAuthorized>
</AuthorizeView>

@code {
    [Inject]
    private NavigationManager NavigationManager { get; set; }

    [Inject]
    private IAccessTokenProvider TokenProvider { get; set; }

    private async Task Login()
    {
        var authProps = new AuthenticationProperties
        {
            RedirectUri = NavigationManager.Uri,
            Items = { ["policy"] = "B2C_1_SIGN_IN" }
        };
        await TokenProvider.LoginAsync(authProps);
    }

    private async Task SignUp()
    {
        var authProps = new AuthenticationProperties
        {
            RedirectUri = "/register-complete",
            Items = { ["policy"] = "B2C_1_SIGN_UP" }
        };
        await TokenProvider.LoginAsync(authProps);
    }

    private async Task Logout()
    {
        var authProps = new AuthenticationProperties
        {
            RedirectUri = NavigationManager.Uri,
            Items = { ["policy"] = "B2C_1_SIGN_IN" }
        };
        await TokenProvider.LogoutAsync(authProps);
    }
}

二、服务器端配置调整

1. 更新appsettings.json

添加两个独立策略的配置项:

"AzureAdB2C": {
  "Instance": "https://***.b2clogin.com/",
  "ClientId": "***",
  "Domain": "**.onmicrosoft.com",
  "Scopes": "API.ReadWrite",
  "SignInPolicyId": "B2C_1_SIGN_IN",
  "SignUpPolicyId": "B2C_1_SIGN_UP"
}

2. 配置多策略认证支持

在Program.cs中调整认证服务,允许两个策略的token通过验证:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAdB2C"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

// 配置多策略支持
builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    var instance = builder.Configuration["AzureAdB2C:Instance"];
    var domain = builder.Configuration["AzureAdB2C:Domain"];
    var signInPolicy = builder.Configuration["AzureAdB2C:SignInPolicyId"];
    var signUpPolicy = builder.Configuration["AzureAdB2C:SignUpPolicyId"];

    // 设置允许的颁发者列表
    options.TokenValidationParameters.ValidIssuers = new[]
    {
        $"{instance}{domain}/{signInPolicy}/v2.0/",
        $"{instance}{domain}/{signUpPolicy}/v2.0/"
    };
});

三、注册后创建本地用户

1. 客户端注册完成回调页

创建RegisterComplete.razor页面,注册成功后调用API创建本地用户:

@page "/register-complete"
@inject HttpClient Http
@inject NavigationManager NavigationManager

<h3>Completing Registration...</h3>

@code {
    protected override async Task OnInitializedAsync()
    {
        try
        {
            // 获取当前用户身份信息
            var userInfo = await Http.GetFromJsonAsync<UserInfo>("/api/userinfo");
            // 调用后端API创建本地用户
            await Http.PostAsJsonAsync("/api/local-users", new { UserId = userInfo.Sub, Email = userInfo.Email });
            // 跳转至主页
            NavigationManager.NavigateTo("/");
        }
        catch
        {
            NavigationManager.NavigateTo("/error");
        }
    }

    public class UserInfo
    {
        public string Sub { get; set; }
        public string Email { get; set; }
    }
}

2. 服务器端API实现

添加两个API控制器,分别用于获取用户信息和创建本地用户:

// UserInfoController.cs
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class UserInfoController : ControllerBase
{
    [HttpGet]
    public IActionResult GetUserInfo()
    {
        var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
        var email = User.FindFirstValue(ClaimTypes.Email);
        return Ok(new { Sub = userId, Email = email });
    }
}

// LocalUsersController.cs
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class LocalUsersController : ControllerBase
{
    private readonly ApplicationDbContext _dbContext;

    public LocalUsersController(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpPost]
    public async Task<IActionResult> CreateLocalUser([FromBody] LocalUserRequest request)
    {
        // 避免重复创建用户
        var existingUser = await _dbContext.LocalUsers.FirstOrDefaultAsync(u => u.UserId == request.UserId);
        if (existingUser != null) return Ok();

        var localUser = new LocalUser
        {
            UserId = request.UserId,
            Email = request.Email,
            CreatedAt = DateTime.UtcNow
        };

        _dbContext.LocalUsers.Add(localUser);
        await _dbContext.SaveChangesAsync();

        return Ok();
    }

    public class LocalUserRequest
    {
        public string UserId { get; set; }
        public string Email { get; set; }
    }
}

关键注意事项

  • 确保Azure AD B2C后台已创建B2C_1_SIGN_IN和B2C_1_SIGN_UP两个独立用户流,且客户端应用已在两个流中启用。
  • 本地用户创建逻辑需保证幂等性,防止重复插入数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:01:28