Open Closed

How to implement OTP Login using balzor web app and auth server(openiddict) #9900


User avatar
0
mc86 created

HI: I had my customgrant named EmployeeNumberGrant `public class EmployeeNumberGrant : ITokenExtensionGrant { public const string ExtensionGrantName = "employee_number";

public string Name => ExtensionGrantName;

private  IdentityUserManager _userManager;
private  IUserClaimsPrincipalFactory<IdentityUser> _claimsFactory;
private  AbpOpenIddictClaimsPrincipalManager _claimsPrincipalManager;
private AbpSignInManager _signInManager;
public EmployeeNumberGrant(
    IdentityUserManager userManager,
    IUserClaimsPrincipalFactory<IdentityUser> claimsFactory,
    AbpOpenIddictClaimsPrincipalManager claimsPrincipalManager)
{
    _userManager = userManager;
    _claimsFactory = claimsFactory;
    _claimsPrincipalManager = claimsPrincipalManager;
    
}

public EmployeeNumberGrant()
{
    

}

public async Task<IActionResult> HandleAsync(ExtensionGrantContext context)
{
    _userManager = context.HttpContext.RequestServices.GetRequiredService<IdentityUserManager>();
    _claimsFactory = context.HttpContext.RequestServices.GetRequiredService<IUserClaimsPrincipalFactory<IdentityUser>>();
    _claimsPrincipalManager = context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimsPrincipalManager>();
    _signInManager= context.HttpContext.RequestServices.GetRequiredService<AbpSignInManager>();
    var empNo = context.Request.GetParameter("employee_number")?.ToString();
    var ts = context.Request.GetParameter("timestamp")?.ToString();
    var signature = context.Request.GetParameter("signature")?.ToString();

    if (string.IsNullOrEmpty(empNo) || string.IsNullOrEmpty(ts) || string.IsNullOrEmpty(signature))
    {
        return new ForbidResult(new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
            new AuthenticationProperties(new Dictionary<string, string>
            {
                [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest,
                [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "Missing parameters."
            }));
    }

    // 1. 校验时间戳
    if (!long.TryParse(ts, out var ticks) ||
        DateTime.UtcNow - new DateTime(ticks, DateTimeKind.Utc) > TimeSpan.FromMinutes(5))
    {
        return new ForbidResult(new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
            new AuthenticationProperties(new Dictionary<string, string>
            {
                [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "Expired timestamp."
            }));
    }

    // 2. 校验签名
    var raw = $"{empNo}:{ts}";
    if (!VerifySignature(raw, signature, "SuperSecretSharedKey123!"))
    {
        return new ForbidResult(new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
            new AuthenticationProperties(new Dictionary<string, string>
            {
                [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "Invalid signature."
            }));
    }

    // 3. 查找用户
    var user = await _userManager.FindByNameAsync(empNo);
    if (user == null)
    {
        return new ForbidResult(new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
            new AuthenticationProperties(new Dictionary<string, string>
            {
                [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "User not found."
            }));
    }

    // 4. 创建 ClaimsPrincipal
    var principal = await _claimsFactory.CreateAsync(user);

    // 附加自定义 Claim
    ((ClaimsIdentity)principal.Identity!).AddClaim("employee_number", empNo);

    // 设置 scopes
    var scopes = new[] {"profile", "roles", "email", "phone", "offline_access", "master9" }.ToImmutableArray();
    principal.SetScopes(scopes);

    // 关联资源
    var resources = new List<string>();
    await foreach (var resource in context.HttpContext.RequestServices
                       .GetRequiredService<IOpenIddictScopeManager>()
                       .ListResourcesAsync(scopes))
    {
        resources.Add(resource);
    }
    principal.SetResources(resources);
    principal.SetAudiences("Master9");
    // 交给 ABP 内置 ClaimsPrincipalManager 处理(角色、权限等)
    await _claimsPrincipalManager.HandleAsync(context.Request, principal);
    //principal.SetScopes(context.Request.GetScopes());

 
   // await _signInManager.SignInAsync(user, isPersistent: false);
    return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, principal);
}

private static bool VerifySignature(string raw, string signature, string secretKey)
{
    using var hmac = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(secretKey));
    var hash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(raw));
    var expected = Convert.ToBase64String(hash);
    return expected == signature;
}

}`

now I don't know how to make blazor app login with this grant.


22 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent

    To enable your Blazor Web App to log in using your custom OpenIddict grant type (e.g., "employee_number"), you need to customize the authentication flow to request a token from the AuthServer using your custom grant. The Blazor template uses OpenID Connect by default, but you can perform a direct token request using HTTP.

    Here’s how you can implement OTP login with your custom grant in a Blazor Web App:

    1. Expose the Custom Grant on AuthServer

      • Ensure your AuthServer is configured to accept the "employee_number" grant type and that the client (Blazor app) has permission for this grant.
    2. Create a Service in Blazor to Request the Token

      • Use HttpClient to POST to /connect/token with the required parameters.

      Example service:

    public class OtpLoginService
       {
           private readonly HttpClient _httpClient;
    
           public OtpLoginService(HttpClient httpClient)
           {
               _httpClient = httpClient;
           }
    
           public async Task<TokenResponse> LoginWithEmployeeNumberAsync(string employeeNumber, string timestamp, string signature)
           {
               var parameters = new Dictionary<string, string>
               {
                   { "grant_type", "employee_number" },
                   { "employee_number", employeeNumber },
                   { "timestamp", timestamp },
                   { "signature", signature },
                   { "client_id", "<YourClientId>" },
                   { "client_secret", "<YourClientSecret>" }, // if required
                   { "scope", "profile roles email phone offline_access master9" }
               };
    
               var content = new FormUrlEncodedContent(parameters);
               var response = await _httpClient.PostAsync("https://<auth-server-url>/connect/token", content);
    
               response.EnsureSuccessStatusCode();
               var json = await response.Content.ReadAsStringAsync();
               return JsonSerializer.Deserialize<TokenResponse>(json);
           }
       }
    
       public class TokenResponse
       {
           public string access_token { get; set; }
           public string token_type { get; set; }
           public int expires_in { get; set; }
           public string refresh_token { get; set; }
       }
    
    1. Store and Use the Token in Blazor

      • After receiving the token, store it (e.g., in local storage) and update the authentication state.
      • You may need to implement a custom AuthenticationStateProvider to use the token for authenticated API calls.
    2. Trigger the Login Flow

      • Call your OtpLoginService.LoginWithEmployeeNumberAsync from your Blazor login page/component when the user submits their OTP.
    3. Update the Authentication State

      • After a successful login, update the authentication state so the Blazor app recognizes the user as logged in.

    Note: The default Blazor OIDC authentication flow does not support custom grant types out-of-the-box. You must handle the token acquisition and authentication state update manually as shown above.

    References:

    This approach aligns with common ABP and OpenIddict extension grant usage for custom authentication scenarios.


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    now I don't know how to make blazor app login with this grant.

    The EmployeeNumberGrant is generally used for Angular.

    The Blazor Server or WASM will use Cookie and OpenID Connect for authentication. It will not use your EmployeeNumberGrant

    Thanks.

  • User Avatar
    0
    mc86 created

    hi maliming how Blazor Server or WASM implement passwordless login. like use a link redrickt to Blazor Server and keep a user login. I had a EmployeeNumberGrantHandler too. ` public class EmployeeNumberGrantHandler : IOpenIddictServerHandler<OpenIddictServerEvents.HandleTokenRequestContext> { public static OpenIddictServerHandlerDescriptor Descriptor { get; } = OpenIddictServerHandlerDescriptor.CreateBuilder<OpenIddictServerEvents.HandleTokenRequestContext>() .UseScopedHandler

      private readonly IdentityUserManager _userManager;
    
      public EmployeeNumberGrantHandler(IdentityUserManager userManager)
      {
          _userManager = userManager;
      }
    
      public async ValueTask HandleAsync(OpenIddictServerEvents.HandleTokenRequestContext context)
      {
          try
          {
              if (!string.Equals(context.Request.GrantType, "employee_number", StringComparison.Ordinal))
                  return ;
    
              var empNo = context.Request["employee_number"]?.ToString();
              var ts = context.Request["timestamp"]?.ToString();
              var signature = context.Request["signature"]?.ToString();
    
              if (string.IsNullOrEmpty(empNo) || string.IsNullOrEmpty(ts) || string.IsNullOrEmpty(signature))
              {
                  context.Reject(OpenIddictConstants.Errors.InvalidRequest, "Missing parameters.");
                  return  ;
              }
    
              // 1. 检查时间戳有效性
              if (!long.TryParse(ts, out var ticks) ||
                  DateTime.UtcNow - new DateTime(ticks, DateTimeKind.Utc) > TimeSpan.FromMinutes(5))
              {
                  context.Reject(OpenIddictConstants.Errors.InvalidGrant, "Expired timestamp.");
                  return  ;
              }
    
              // 2. 验证签名
              var raw = $"{empNo}:{ts}";
              if (!VerifySignature(raw, signature, "SuperSecretSharedKey123!"))
              {
                  context.Reject(OpenIddictConstants.Errors.InvalidGrant, "Invalid signature.");
                  return  ;
              }
    
              // 3. 查找用户
              var user = await _userManager.FindByNameAsync(empNo);
              if (user == null)
              {
                  context.Reject(OpenIddictConstants.Errors.InvalidGrant, "User not found.");
                  return;
              }
    
              // 4. 创建 ClaimsIdentity
              var identity = new ClaimsIdentity(
                  TokenValidationParameters.DefaultAuthenticationType,
                  OpenIddictConstants.Claims.Name,
                  OpenIddictConstants.Claims.Role);
    
              // subject(必须)
              var subject = new Claim(OpenIddictConstants.Claims.Subject, user.Id.ToString());
              subject.SetDestinations(OpenIddictConstants.Destinations.AccessToken,
                                      OpenIddictConstants.Destinations.IdentityToken);
              identity.AddClaim(subject);
    
              // 用户名
              var name = new Claim(OpenIddictConstants.Claims.Name, user.UserName ?? empNo);
              name.SetDestinations(OpenIddictConstants.Destinations.AccessToken,
                                   OpenIddictConstants.Destinations.IdentityToken);
              identity.AddClaim(name);
    
              // 工号
              var empNoClaim = new Claim("employee_number", empNo);
              empNoClaim.SetDestinations(OpenIddictConstants.Destinations.AccessToken,
                                         OpenIddictConstants.Destinations.IdentityToken);
              identity.AddClaim(empNoClaim);
    
              // 5. 创建 principal
              var principal = new ClaimsPrincipal(identity);
    
              // 给 token 添加 scopes(至少 openid/profile,客户端必须要请求)
              principal.SetScopes(new[]
              {
                  OpenIddictConstants.Scopes.OpenId,
                  OpenIddictConstants.Scopes.Profile,
                  OpenIddictConstants.Scopes.Email,
                  OpenIddictConstants.Scopes.Roles
              }.Intersect(context.Request.GetScopes()));
    
              // 可以给 access_token 附加 API 资源
              principal.SetResources("resource_server");
    
              context.Principal = principal;
              context.SignIn(principal);
              context.HandleRequest(); 
          }
          catch (Exception ex)
          {
              context.Reject(OpenIddictConstants.Errors.InvalidGrant, ex.Message);
              return  ;
          }
         
           
      }
    
      private static bool VerifySignature(string raw, string signature, string secretKey)
      {
          using var hmac = new System.Security.Cryptography.HMACSHA256(System.Text.Encoding.UTF8.GetBytes(secretKey));
          var hash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(raw));
          var expected = Convert.ToBase64String(hash);
          return expected == signature;
      }
    

    }`

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The Blazor Server and WASM use different authentication methods.

    In a short, Blazor Server and WASM can't use your EmployeeNumberGrant

    Thanks,.

  • User Avatar
    0
    mc86 created

    I know they use Cookie or OpenID Connect , But I'd like to Know how Blazor Server and WASM implement Passwordless Login with auth server.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Blazor Server and WASM apps can only redirect to the AuthServer project to sign in(code flow).

    Thanks.

  • User Avatar
    0
    mc86 created

    Chould you give me more infomation about how to do it ? like step by step. what i need to do in both blazor and AuthServer? thanks a lot.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    默认的项目模版就是这样工作的.

    Blazor Server 或者 WASM 会使用code流通过AuthServer完成认证(获取access token/ id token).

    你的最终需求是在authserver中完成登录吗?

    谢谢

  • User Avatar
    0
    mc86 created

    通过链接用一次性密码在authserver中完成登陆.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    你可以在authserver中这样做, 之后blazor server 或者 wasm要主动触发认证, 然后重定向到authserver中, 完成认证后再次重定向会应用中. 请参考https://abp.io/community/articles/implementing-passwordless-authentication-with-asp.net-core-identity-c25l8koj

  • User Avatar
    0
    mc86 created

    1.请求autheserver的passwordlesscontroller. 完成signin 2.打开blazor server 或者wassm的有认证要求的页面 3.自动跳转到autheserver,无需输入密码 4.autheserver跳转回请求页面 是这也吗

    能不能直接打开blazor sever的页面A,在A中请求passwordlesscontroller. 然后触发认证?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    理论上没有问题, 你可以参考https://abp.io/community/articles/implementing-passwordless-authentication-with-asp.net-core-identity-c25l8koj 试试看

  • User Avatar
    0
    mc86 created

    好的 我试一下,谢谢~

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    好的

  • User Avatar
    0
    mc86 created

    你好 现在有问题,可能是什么导致的呢? 我使用https://authserver:28443/Passwordless/Login?userId=0630&token=123 跳转到authserver的Passwordless

    可以正常跳转,跳转后进入页面开始验证.但是最终会跳转到Logout

    ` [HttpGet("Login")] public virtual async Task

     await UserManager.UpdateSecurityStampAsync(user);
    
      await SignInManager.SignInAsync(user, isPersistent: false);
    
     var blazorserver= "http://blazorserver:28444";
     return Redirect(blazorserver);
    

    }`

    BLAZOR -log

    2025-09-18 10:41:00.187 +08:00 [INF] Request starting HTTP/1.1 GET http://master.aysdlrmyy.com:28444/ - null null 2025-09-18 10:41:00.187 +08:00 [INF] Executing endpoint '/ (/)' 2025-09-18 10:41:00.192 +08:00 [WRN] Could not find IdentityClientConfiguration for AbpMvcClient. Either define a configuration for AbpMvcClient or set a default configuration. 2025-09-18 10:41:00.192 +08:00 [INF] Start processing HTTP request GET https://master.aysdlrmyy.com:28445/api/abp/application-configuration?* 2025-09-18 10:41:00.192 +08:00 [INF] Sending HTTP request GET https://master.aysdlrmyy.com:28445/api/abp/application-configuration?* 2025-09-18 10:41:00.250 +08:00 [INF] Received HTTP response headers after 57.9971ms - 200 2025-09-18 10:41:00.250 +08:00 [INF] End processing HTTP request after 58.2247ms - 200 2025-09-18 10:41:00.251 +08:00 [WRN] Could not find IdentityClientConfiguration for AbpMvcClient. Either define a configuration for AbpMvcClient or set a default configuration. 2025-09-18 10:41:00.251 +08:00 [INF] Start processing HTTP request GET https://master.aysdlrmyy.com:28445/api/abp/application-localization?* 2025-09-18 10:41:00.251 +08:00 [INF] Sending HTTP request GET https://master.aysdlrmyy.com:28445/api/abp/application-localization?* 2025-09-18 10:41:00.392 +08:00 [INF] Received HTTP response headers after 141.242ms - 200 2025-09-18 10:41:00.392 +08:00 [INF] End processing HTTP request after 141.4583ms - 200 2025-09-18 10:41:00.394 +08:00 [INF] Authorization failed. These requirements were not met: PermissionRequirement: SettingManagement.Emailing

    AUTH-SERVER 2025-09-18 10:41:00.070 +08:00 [INF] Request starting HTTP/2 GET https://master.aysdlrmyy.com:28443/Passwordless/Login?userId=admin&token=123 - null null 2025-09-18 10:41:00.073 +08:00 [INF] Executing endpoint 'Master9.Custom.PasswordlessController.Login (Master9.AuthServer)' 2025-09-18 10:41:00.073 +08:00 [INF] Route matched with {action = "Login", controller = "Passwordless", area = "", page = ""}. Executing controller action with signature System.Threading.Tasks.Task1[Microsoft.AspNetCore.Mvc.IActionResult] Login(System.String, System.String) on controller Master9.Custom.PasswordlessController (Master9.AuthServer). 2025-09-18 10:41:00.167 +08:00 [INF] AuthenticationScheme: Identity.Application signed in. 2025-09-18 10:41:00.169 +08:00 [INF] Executing RedirectResult, redirecting to http://master.aysdlrmyy.com:28444. 2025-09-18 10:41:00.169 +08:00 [INF] Executed action Master9.Custom.PasswordlessController.Login (Master9.AuthServer) in 96.0496ms 2025-09-18 10:41:00.169 +08:00 [INF] Executed endpoint 'Master9.Custom.PasswordlessController.Login (Master9.AuthServer)' 2025-09-18 10:41:00.171 +08:00 [INF] Request finished HTTP/2 GET https://master.aysdlrmyy.com:28443/Passwordless/Login?userId=admin&token=123 - 302 null null 101.0982ms 2025-09-18 10:41:05.135 +08:00 [INF] Request starting HTTP/2 GET https://master.aysdlrmyy.com:28443/connect/logout?post_logout_redirect_uri=http%3A%2F%2Fmaster.aysdlrmyy.com%3A28444%2Fsignout-callback-oidc&state=CfDJ8D2ygYFMKaZGvAEpZ3bmx8lReZ3O7KYHF1W13nbjz63FeaXjQWKJ-wBoj9J1H7UXTDAAAuB2CIFIwOXP2pJETFdea2hXUO2mpi9Jx2dBIVoS-6SwSZcCJ00gYo3K6eLy1wXoVpL82stixCDdakYY7pA&x-client-SKU=ID_NET9_0&x-client-ver=8.1.0.0 - null null 2025-09-18 10:41:05.136 +08:00 [INF] The request URI matched a server endpoint: "Logout". 2025-09-18 10:41:05.136 +08:00 [INF] The logout request was successfully extracted: { "post_logout_redirect_uri": "http://master.aysdlrmyy.com:28444/signout-callback-oidc", "state": "CfDJ8D2ygYFMKaZGvAEpZ3bmx8lReZ3O7KYHF1W13nbjz63FeaXjQWKJ-wBoj9J1H7UXTDAAAuB2CIFIwOXP2pJETFdea2hXUO2mpi9Jx2dBIVoS-6SwSZcCJ00gYo3K6eLy1wXoVpL82stixCDdakYY7pA", "x-client-SKU": "ID_NET9_0", "x-client-ver": "8.1.0.0" }. 2025-09-18 10:41:05.139 +08:00 [INF] The logout request was rejected because the specified post_logout_redirect_uri was invalid: http://master.aysdlrmyy.com:28444/signout-callback-oidc. 2025-09-18 10:41:05.139 +08:00 [INF] Request finished HTTP/2 GET https://master.aysdlrmyy.com:28443/connect/logout?post_logout_redirect_uri=http%3A%2F%2Fmaster.aysdlrmyy.com%3A28444%2Fsignout-callback-oidc&state=CfDJ8D2ygYFMKaZGvAEpZ3bmx8lReZ3O7KYHF1W13nbjz63FeaXjQWKJ-wBoj9J1H7UXTDAAAuB2CIFIwOXP2pJETFdea2hXUO2mpi9Jx2dBIVoS-6SwSZcCJ00gYo3K6eLy1wXoVpL82stixCDdakYY7pA&x-client-SKU=ID_NET9_0&x-client-ver=8.1.0.0 - 302 null null 4.0188ms 2025-09-18 10:41:05.141 +08:00 [INF] Request starting HTTP/2 GET https://master.aysdlrmyy.com:28443/Error?httpStatusCode=400 - null null 2025-09-18 10:41:05.213 +08:00 [INF] Executing endpoint 'Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Controllers.ErrorController.Index (Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared)' 2025-09-18 10:41:05.213 +08:00 [INF] Route matched with {action = "Index", controller = "Error", area = "", page = ""}. Executing controller action with signature System.Threading.Tasks.Task1[Microsoft.AspNetCore.Mvc.IActionResult] Index(Int32) on controller Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Controllers.ErrorController (Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared). 2025-09-18 10:41:05.221 +08:00 [INF] Executing ViewResult, running view ~/Views/Error/Default.cshtml. 2025-09-18 10:41:05.239 +08:00 [INF] Executed ViewResult - view ~/Views/Error/Default.cshtml executed in 17.2282ms. 2025-09-18 10:41:05.239 +08:00 [INF] Executed action Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Controllers.ErrorController.Index (Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared) in 25.4387ms 2025-09-18 10:41:05.239 +08:00 [INF] Executed endpoint 'Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Controllers.ErrorController.Index (Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared)'

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Add the URL below to your client/application's post_logout_redirect_uri

    The logout request was rejected because the specified post_logout_redirect_uri was invalid: 
    
    http://master.aysdlrmyy.com:28444/signout-callback-oidc.
    
  • User Avatar
    0
    mc86 created

    添加后没有报错了 但是会反复触发认证

    2025-09-18 11:53:30.764 +08:00 [INF] AuthenticationScheme: Cookies signed out. 2025-09-18 11:53:30.765 +08:00 [INF] Executing SignOutResult with authentication schemes (["oidc"]). 2025-09-18 11:53:30.765 +08:00 [INF] AuthenticationScheme: oidc signed out. 2025-09-18 11:53:30.765 +08:00 [INF] Executed action Master9.Blazor.Controllers.AccountController.LogoutAsync (Master9.Blazor) in 1.645ms 2025-09-18 11:53:30.765 +08:00 [INF] Executed endpoint 'Master9.Blazor.Controllers.AccountController.LogoutAsync (Master9.Blazor)' 2025-09-18 11:53:30.765 +08:00 [INF] Request finished HTTP/1.1 GET http://master.aysdlrmyy.com:28444/Account/Logout - 302 null null 2.9495ms 2025-09-18 11:53:30.770 +08:00 [INF] Request starting HTTP/1.1 GET http://master.aysdlrmyy.com:28444/_content/Blazorise/vendors/jsencrypt.js?v=1.6.2.0 - null null 2025-09-18 11:53:30.770 +08:00 [INF] Request starting HTTP/1.1 GET http://master.aysdlrmyy.com:28444/_content/Blazorise/vendors/sha512.js?v=1.6.2.0 - null null 2025-09-18 11:53:30.770 +08:00 [INF] Executing endpoint 'Microsoft.AspNetCore.Routing.RouteEndpoint' 2025-09-18 11:53:30.770 +08:00 [INF] Executing endpoint 'Microsoft.AspNetCore.Routing.RouteEndpoint' 2025-09-18 11:53:30.770 +08:00 [INF] The file _content/Blazorise/vendors/sha512.js was not modified 2025-09-18 11:53:30.770 +08:00 [INF] The file _content/Blazorise/vendors/jsencrypt.js was not modified 2025-09-18 11:53:30.770 +08:00 [INF] Executed endpoint 'Microsoft.AspNetCore.Routing.RouteEndpoint' 2025-09-18 11:53:30.770 +08:00 [INF] Executed endpoint 'Microsoft.AspNetCore.Routing.RouteEndpoint' 2025-09-18 11:53:30.770 +08:00 [INF] Request finished HTTP/1.1 GET http://master.aysdlrmyy.com:28444/_content/Blazorise/vendors/sha512.js?v=1.6.2.0 - 304 null text/javascript 0.6231ms 2025-09-18 11:53:30.770 +08:00 [INF] Request finished HTTP/1.1 GET http://master.aysdlrmyy.com:28444/_content/Blazorise/vendors/jsencrypt.js?v=1.6.2.0 - 304 null text/javascript 0.7513ms 2025-09-18 11:53:30.785 +08:00 [INF] Request starting HTTP/1.1 GET http://master.aysdlrmyy.com:28444/signout-callback-oidc?state=CfDJ8D2ygYFMKaZGvAEpZ3bmx8mpxka9ME4C9_R_kPwnxdQmQMtUUzUlU8U5mlflyQPoFlbyPPrLyu8RDUIaH4pkgGSD2KIpU75HGeHihfjzq_OUXVTcHK74pYeXreKlgTGoId_rywR_ykAcc6NxzHrY2zA - null null 2025-09-18 11:53:30.786 +08:00 [INF] Request finished HTTP/1.1 GET http://master.aysdlrmyy.com:28444/signout-callback-oidc?state=CfDJ8D2ygYFMKaZGvAEpZ3bmx8mpxka9ME4C9_R_kPwnxdQmQMtUUzUlU8U5mlflyQPoFlbyPPrLyu8RDUIaH4pkgGSD2KIpU75HGeHihfjzq_OUXVTcHK74pYeXreKlgTGoId_rywR_ykAcc6NxzHrY2zA - 302 null null 0.5648ms 2025-09-18 11:53:30.790 +08:00 [INF] Request starting HTTP/1.1 GET http://master.aysdlrmyy.com:28444/ - null null 2025-09-18 11:53:30.790 +08:00 [INF] Executing endpoint '/ (/)' 2025-09-18 11:53:30.794 +08:00 [INF] Authorization failed. These requirements were not met: PermissionRequirement: SettingManagement.Emailing 2025-09-18 11:53:30.794 +08:00 [INF] Authorization failed. These requirements were not met: PermissionRequirement: AbpAccount.SettingManagement

    auth 2025-09-18 11:52:57.339 +08:00 [INF] Request starting HTTP/2 GET https://master.aysdlrmyy.com:28443/Passwordless/Login?userId=admin&token=123 - null null 2025-09-18 11:52:57.343 +08:00 [INF] Executing endpoint 'Master9.Custom.PasswordlessController.Login (Master9.AuthServer)' 2025-09-18 11:52:57.352 +08:00 [INF] Route matched with {action = "Login", controller = "Passwordless", area = "", page = ""}. Executing controller action with signature System.Threading.Tasks.Task1[Microsoft.AspNetCore.Mvc.IActionResult] Login(System.String, System.String) on controller Master9.Custom.PasswordlessController (Master9.AuthServer). 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'AmountMax' on entity type 'ContractAmount'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'AmountMini' on entity type 'ContractAmount'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'Amount' on entity type 'ContractMain'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'Amount' on entity type 'DefaultRecord'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'Amount' on entity type 'PayRecord'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'Proportion' on entity type 'PayTypeProgress'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'Amount' on entity type 'WarrantyPeriod'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'PayedAmount' on entity type 'WarrantyPeriod'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:58.325 +08:00 [WRN] No store type was specified for the decimal property 'RemainingAmount' on entity type 'WarrantyPeriod'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values in 'OnModelCreating' using 'HasColumnType', specify precision and scale using 'HasPrecision', or configure a value converter using 'HasConversion'. 2025-09-18 11:52:59.746 +08:00 [INF] Request starting HTTP/2 GET https://master.aysdlrmyy.com:28443/connect/logout?post_logout_redirect_uri=http%3A%2F%2Fmaster.aysdlrmyy.com%3A28444%2Fsignout-callback-oidc&state=CfDJ8D2ygYFMKaZGvAEpZ3bmx8nlI0RZ1T2yW3STyka3CVCJdWCeCIQ5xjsJN2E27Dbw0Ij7SykGqpfp1HnIY2SxynCmU8n5LBClCDG86__9HwEUjnVPTboCwx4an3s14n0xEcF6GLCZGb3XMNh_PNfWzb4&x-client-SKU=ID_NET9_0&x-client-ver=8.1.0.0 - null null 2025-09-18 11:52:59.747 +08:00 [INF] The request URI matched a server endpoint: "Logout". 2025-09-18 11:52:59.748 +08:00 [INF] The logout request was successfully extracted: { "post_logout_redirect_uri": "http://master.aysdlrmyy.com:28444/signout-callback-oidc", "state": "CfDJ8D2ygYFMKaZGvAEpZ3bmx8nlI0RZ1T2yW3STyka3CVCJdWCeCIQ5xjsJN2E27Dbw0Ij7SykGqpfp1HnIY2SxynCmU8n5LBClCDG86__9HwEUjnVPTboCwx4an3s14n0xEcF6GLCZGb3XMNh_PNfWzb4", "x-client-SKU": "ID_NET9_0", "x-client-ver": "8.1.0.0" }. 2025-09-18 11:52:59.751 +08:00 [INF] The logout request was successfully validated. 2025-09-18 11:52:59.751 +08:00 [WRN] No SessionId was found in the token during HandleLogoutRequestContext. 2025-09-18 11:52:59.754 +08:00 [INF] Executing endpoint 'Volo.Abp.OpenIddict.Controllers.LogoutController.GetAsync (Volo.Abp.OpenIddict.AspNetCore)' 2025-09-18 11:52:59.754 +08:00 [INF] Route matched with {action = "Get", controller = "Logout", area = "", page = ""}. Executing controller action with signature System.Threading.Tasks.Task1[Microsoft.AspNetCore.Mvc.IActionResult] GetAsync() on controller Volo.Abp.OpenIddict.Controllers.LogoutController (Volo.Abp.OpenIddict.AspNetCore). 2025-09-18 11:52:59.756 +08:00 [ERR] SessionId is null. It's not possible to revoke the session during sign out. 2025-09-18 11:52:59.756 +08:00 [INF] AuthenticationScheme: Identity.Application signed out. 2025-09-18 11:52:59.757 +08:00 [INF] AuthenticationScheme: Identity.External signed out. 2025-09-18 11:52:59.757 +08:00 [INF] AuthenticationScheme: Identity.TwoFactorUserId signed out. 2025-09-18 11:52:59.757 +08:00 [INF] Executing SignOutResult with authentication schemes (["OpenIddict.Server.AspNetCore"]). 2025-09-18 11:52:59.757 +08:00 [INF] The logout response was successfully returned to 'http://master.aysdlrmyy.com:28444/signout-callback-oidc': { "state": "CfDJ8D2ygYFMKaZGvAEpZ3bmx8nlI0RZ1T2yW3STyka3CVCJdWCeCIQ5xjsJN2E27Dbw0Ij7SykGqpfp1HnIY2SxynCmU8n5LBClCDG86__9HwEUjnVPTboCwx4an3s14n0xEcF6GLCZGb3XMNh_PNfWzb4" }. 2025-09-18 11:52:59.757 +08:00 [INF] Executed action Volo.Abp.OpenIddict.Controllers.LogoutController.GetAsync (Volo.Abp.OpenIddict.AspNetCore) in 3.2291ms 2025-09-18 11:52:59.757 +08:00 [INF] Executed endpoint 'Volo.Abp.OpenIddict.Controllers.LogoutController.GetAsync (Volo.Abp.OpenIddict.AspNetCore)' 2025-09-18 11:52:59.758 +08:00 [INF] Request finished HTTP/2 GET https://master.aysdlrmyy.com:28443/connect/logout?post_logout_redirect_uri=http%3A%2F%2Fmaster.aysdlrmyy.com%3A28444%2Fsignout-callback-oidc&state=CfDJ8D2ygYFMKaZGvAEpZ3bmx8nlI0RZ1T2yW3STyka3CVCJdWCeCIQ5xjsJN2E27Dbw0Ij7SykGqpfp1HnIY2SxynCmU8n5LBClCDG86__9HwEUjnVPTboCwx4an3s14n0xEcF6GLCZGb3XMNh_PNfWzb4&x-client-SKU=ID_NET9_0&x-client-ver=8.1.0.0 - 302 null null 11.5585ms 2025-09-18 11:53:02.544 +08:00 [INF] AuthenticationScheme: Identity.Application signed in. 2025-09-18 11:53:02.573 +08:00 [INF] Executing RedirectResult, redirecting to http://master.aysdlrmyy.com:28444. 2025-09-18 11:53:02.574 +08:00 [INF] Executed action Master9.Custom.PasswordlessController.Login (Master9.AuthServer) in 5220.9766ms 2025-09-18 11:53:02.574 +08:00 [INF] Executed endpoint 'Master9.Custom.PasswordlessController.Login (Master9.AuthServer)' 2025-09-18 11:53:02.596 +08:00 [INF] Request finished HTTP/2 GET https://master.aysdlrmyy.com:28443/Passwordless/Login?userId=admin&token=123 - 302 null null 5256.7679ms 2025-09-18 11:53:07.343 +08:00 [INF] Request starting HTTP/2 GET https://master.aysdlrmyy.com:28443/connect/logout?post_logout_redirect_uri=http%3A%2F%2Fmaster.aysdlrmyy.com%3A28444%2Fsignout-callback-oidc&state=CfDJ8D2ygYFMKaZGvAEpZ3bmx8mXYQRNhVaWzNEccmcV4GBfYq81JmwQk3CM6-nVYKCEh07MTUw98Ky7mnbURVkgRnRxwRxnghylFqkxCQjtlZ0DOTi0t1rRkmzWF6FY2Sb240_s17o-oLDxPqMApS_jNAw&x-client-SKU=ID_NET9_0&x-client-ver=8.1.0.0 - null null 2025-09-18 11:53:07.344 +08:00 [INF] The request URI matched a server endpoint: "Logout". 2025-09-18 11:53:07.344 +08:00 [INF] The logout request was successfully extracted: { "post_logout_redirect_uri": "http://master.aysdlrmyy.com:28444/signout-callback-oidc", "state": "CfDJ8D2ygYFMKaZGvAEpZ3bmx8mXYQRNhVaWzNEccmcV4GBfYq81JmwQk3CM6-nVYKCEh07MTUw98Ky7mnbURVkgRnRxwRxnghylFqkxCQjtlZ0DOTi0t1rRkmzWF6FY2Sb240_s17o-oLDxPqMApS_jNAw", "x-client-SKU": "ID_NET9_0", "x-client-ver": "8.1.0.0" }.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    你在blazor server和authserver中的代码是?

  • User Avatar
    0
    mc86 created

    我访问https://master.aysdlrmyy.com:28443/Passwordless/Login?userId=admin&token=123 后自动跳转到blazor的"/"

    authserver

    public class PasswordlessController : AbpController
      {
          protected IdentityUserManager UserManager { get; }
    
          protected AbpSignInManager SignInManager { get; }
    
          public PasswordlessController(IdentityUserManager userManager, AbpSignInManager signInManager)
          {
              UserManager = userManager;
              SignInManager = signInManager;
          }
          [HttpGet("Login")]
          public virtual async Task<IActionResult> Login(string token, string userId)
          {
              var user = await UserManager.FindByNameAsync(userId);
              //测试用 只使用userId 后台直接获取token
              var token2 = await UserManager.GenerateUserTokenAsync(user, "PasswordlessLoginProvider",
                 "passwordless-auth");
              var isValid = await UserManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token2);
              if (!isValid)
              {
                  throw new UnauthorizedAccessException("The token " + token + " is not valid for the user " + userId);
              }
    
              await UserManager.UpdateSecurityStampAsync(user);
    
               await SignInManager.SignInAsync(user, isPersistent: false);
    
              var blazorserver = "http://master.aysdlrmyy.com:28444";
              return Redirect(blazorserver);
          }
      }
    

    blazor

    @page "/"
    @inherits Master9ComponentBase
    @using Contract.FlowUsers
    @using DevExpress.Blazor
    @using Mc;
    @using Microsoft.AspNetCore.Authorization
    @inject IFlowUsersAppService FlowUsersAppService
    @attribute [Authorize]
    <h1>
        123
    </h1>`
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    请先删除现有的logs.txt, 然后复现问题, 之后分享blazor和authserver的日志到 liming.ma@volosoft.com

    谢谢

  • User Avatar
    0
    mc86 created

    已发送

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    好点, 我会检查日志.

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.0.0-preview. Updated on September 18, 2025, 07:10