Open Closed

How-to-configure-separate-authentication-based-on-user-type. #8041


User avatar
0
smansuri created
  • ABP Framework version: v8.2.1

  • UI Type: Angular / MVC / Blazor Server

  • Database System: EF Core (MySQL)

  • Tiered (for MVC) or Auth Server Separated (for Angular): Auth server separated angular

  • Exception message and full stack trace: NA

  • Steps to reproduce the issue: NA

We have use case where we want to configure authentication scheme based on the user type. if a user is not a backend user/company user but a consumer than we want to configure mobile OTP based authentication and for company/tenant backend user , we want to use user name password authentication. Please suggest how to achieve this.


39 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can debug the code to see why return new ForbidResult

    image.png

  • User Avatar
    0
    pvala created
        if (!await userManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", userToken))
    

    This if condition, it's going inside this if block, which it should not.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can check why the code is invalid.

    VerifyUserTokenAsync this is nothing to do with your grant extension

    var token = await UserManager.GenerateUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth");
    await userManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token)
    
  • User Avatar
    0
    pvala created

    Yes, I got the point. But problem what I am dealing with is, earlier I was verifying the code here in this endpoint

    public async Task<VerifyOTPAndSignInResponseDto> VerifyOTPAndSignIn(VerifyOTPAndSignInInput input)
    {
        using (CurrentTenant.Change(input.TenantId))
        {
            using (var unitOfWork = UnitOfWorkManager.Begin())
            {
                try
                {
                    VerifyOTPResponseDto otpVerification = await VerifyOTP(
                        new VerifyOTPInput()
                        {
                            CountryCode = input.CountryCode,
                            MobileNumber = input.MobileNumber,
                            OTP = input.OTP,
                        });
    
                    if (otpVerification.type == "success")
                    {
                        var existingUser = await UserManager.FindByNameAsync(input.CountryCode + input.MobileNumber);
                        var user = new Volo.Abp.Identity.IdentityUser(GuidGenerator.Create(), input.CountryCode + input.MobileNumber, input.CountryCode + input.MobileNumber + "@example.com", null);
                        user.SetPhoneNumber(input.CountryCode + "-" + input.MobileNumber, true);
    
                        if (existingUser == null)
                        {
                            (await UserManager.CreateAsync(user)).CheckErrors();
                            using (CurrentTenant.Change(null))
                            {
                                (await UserManager.AddToRoleAsync(user, "Patient")).CheckErrors();
                            }
                            await UsersAppService.PasswordlessUserRegistration(new PasswordlessUserRegistration(input.CountryCode, input.MobileNumber, user.Id));
                        }
                        else
                        {
                            user = existingUser;
                        }
    
                        var token = await UserManager.GenerateUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth");
    
    // Here I was validating the code
                        //var isValid = await UserManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token);
                        //if (!isValid)
                        //{
                        //    throw new UnauthorizedAccessException("The token " + token + " is not valid for the user " + user.Id);
                        //}
    
                        await UserManager.UpdateSecurityStampAsync(user);
                        await unitOfWork.CompleteAsync();
                        await SignInManager.SignInAsync(user, isPersistent: true);
                        return
                            new VerifyOTPAndSignInResponseDto()
                            {
                                message = otpVerification.message,
                                type = otpVerification.type,
                                token = token
                            };
                    }
                    else
                    {
                        return new VerifyOTPAndSignInResponseDto()
                        {
                            message = otpVerification.message,
                            type = otpVerification.type
                        };
                    }
                }
                catch (Exception e)
                {
                    await unitOfWork.RollbackAsync();
                    unitOfWork.Dispose();
                    throw;
                }
            }
        }
    }
    

    There it was successfully validating it, but when I moved that to the grant extension class, there it does not validate it.

  • User Avatar
    0
    pvala created

    In short, this line of code

    await UserManager.VerifyUserTokenAsync(user, "PasswordlessLoginProvider", "passwordless-auth", token)

    returns true in the controller endpoint, but returns false in the grant extension class, that's the issue.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you prepare a minimal project to reproduce the problem and share it?

    liming.ma@volosoft.com

    Thanks.

  • User Avatar
    0
    pvala created

    Hi, I have given you the access to the git repository : https://github.com/perquantum/passwordless-authentication

    Here I have put the sample project. Here's what you need to do.

    Run the AuthServer project (or the whole solution)
    In postman, hit this api endpoint,

    image.png

    In response, you will get
    {
    "token": "6 digit token",
    "userId": "User Id of the user"
    }

    You need to take these, token and userid values and hit one more API as follows :

    image.png

    In response, the user should be validated. This is the thing we want to achieve.

  • User Avatar
    0
    pvala created

    Also, we are using the MySQL as database, so I have updated the changes in the project accordingly. You can pull the latest changes and try.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    ok, I will check it today.

    Thanks.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you try to remove the await UserManager.UpdateSecurityStampAsync(user); and try again?


    Also, we are using the MySQL as database

    The connection strings are still SQL server.

  • User Avatar
    0
    pvala created

    Hi, that worked. I was able to the access_token. But using that access_token, if I try to get the details of the application configuration, I should get the details of the currentUser right? But I am not getting the details there.

    image.png

    I also parsed the token on https://jwt.io/ the details are coming in as correctly there. But when tried to call the application-configuration api, it doesn't fetch the currentUser details.

    And this is the error we are getting from logs :

    Failed to validate the token.
    Microsoft.IdentityModel.Tokens.SecurityTokenInvalidAudienceException: IDX10206: Unable to validate audience. The 'audiences' parameter is empty.
    at Microsoft.IdentityModel.Tokens.Validators.ValidateAudience(IEnumerable`1 audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
    at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateTokenPayloadAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
    at Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler.ValidateJWSAsync(JsonWebToken jsonWebToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
    [08:06:39 INF] Bearer was not authenticated. Failure message: IDX10206: Unable to validate audience. The 'audiences' parameter is empty.
    [08:06:39 INF] Executing endpoint 'Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationController.GetAsync (Volo.Abp.AspNetCore.Mvc)'

    Can you help.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Try to add scope to connect/token request

    image.png

    Global search the _scopeManager.CreateAsync in your solution.

    await _scopeManager.CreateAsync(new OpenIddictScopeDescriptor {
        Name = "MyProjectName", DisplayName = "MyProjectName API", Resources = { "MyProjectName" }
    });
    
  • User Avatar
    0
    pvala created

    Hi, we have added all the required scope for the client, and after adding the scope, when we hit the connect/token API, we got this result :

    image.png

    Response :

    {
    "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjQwMzkyQUM4QzU2MzZGQTRDQTEzN0Y3NUE0MTI0OUU1MjZBNzU4RjgiLCJ4NXQiOiJRRGtxeU1WamI2VEtFMzkxcEJKSjVTYW5XUGciLCJ0eXAiOiJhdCtqd3QifQ.eyJpc3MiOiJodHRwczovL2Rldi5kb2N0cnouaW46NDQzMjIvIiwiZXhwIjoxNzMxNDA4OTc5LCJpYXQiOjE3MzE0MDUzNzksInNjb3BlIjoib3BlbmlkIiwianRpIjoiODQ2NTgzZjMtYjY5ZC00MmMwLTkzNzQtYjU3ZjgyMjk3YWE1Iiwic3ViIjoiM2ExNjFkZTYtMzk2NC1hNzg3LTRkNmEtOTg3MGRlZjcxNjE5IiwicHJlZmVycmVkX3VzZXJuYW1lIjoiKzkxOTYzODgyODUzMCIsImVtYWlsIjoiKzkxOTYzODgyODUzMEBleGFtcGxlLmNvbSIsInJvbGUiOiJQYXRpZW50IiwicGhvbmVfbnVtYmVyIjoiKzkxLTk2Mzg4Mjg1MzAiLCJwaG9uZV9udW1iZXJfdmVyaWZpZWQiOiJUcnVlIiwiZW1haWxfdmVyaWZpZWQiOiJGYWxzZSIsInNlc3Npb25faWQiOiI3MWY1NWM3Yy1mZTc5LTQ5NmYtODUxMS05MTNlYTg1NTc4MzIiLCJ1bmlxdWVfbmFtZSI6Iis5MTk2Mzg4Mjg1MzAiLCJvaV9wcnN0IjoicmVhY3RuYXR2ZUFwcF9Nb2JpbGUiLCJjbGllbnRfaWQiOiJyZWFjdG5hdHZlQXBwX01vYmlsZSIsIm9pX3Rrbl9pZCI6IjNhMTYzMWZhLTUxMWUtYmNiOS1lYTk0LTI1YWMwMTY0YjhiOSJ9.RCuBvzgy4XksHbFepPAPra-6RUgvHVEvNyn3NiOo47HwJJC4cRks7yfPH6Rvbj3BAf7DZYb9dk63UZLtJPVSCEJpG3xlOt6mx8zK4A6jxrh2nTCJI3MiOgIrsV99K02HqBfBz0kleXja4S8D7MPYAWyXrMOoeNQv6I4bNg9zRDHMh3viyLzkYHz_v6a8C059QplYEnJ9uUNQyiXx-aQGhN-pPbR_bo5PQOSwUdjsOYdvvWp6Tt_rT7V-O98otTigwfaTHSbmSb6C7QJ9VmcyF5D7F0Ll4C6FuraX74kG69wpjMevwP8_Dp_KtxsRTmD9RE4kJfv9kTbiQExEfJmrIQ",
    "token_type": "Bearer",
    "expires_in": 3599,
    "scope": "openid",
    "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjQwMzkyQUM4QzU2MzZGQTRDQTEzN0Y3NUE0MTI0OUU1MjZBNzU4RjgiLCJ4NXQiOiJRRGtxeU1WamI2VEtFMzkxcEJKSjVTYW5XUGciLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2Rldi5kb2N0cnouaW46NDQzMjIvIiwiZXhwIjoxNzMxNDA2NTc5LCJpYXQiOjE3MzE0MDUzNzksImF1ZCI6InJlYWN0bmF0dmVBcHBfTW9iaWxlIiwic3ViIjoiM2ExNjFkZTYtMzk2NC1hNzg3LTRkNmEtOTg3MGRlZjcxNjE5Iiwic2Vzc2lvbl9pZCI6IjcxZjU1YzdjLWZlNzktNDk2Zi04NTExLTkxM2VhODU1NzgzMiIsImF6cCI6InJlYWN0bmF0dmVBcHBfTW9iaWxlIiwiYXRfaGFzaCI6Ijd4U1V0VkxCRkw2bEM1SkxFNDYtSXciLCJvaV90a25faWQiOiIzYTE2MzFmYS01MTJlLWNlZjUtYjFlYi05MzcxODZkNWFlNWUifQ.Vbl0-9tk9oiJpEye-mlWMBiNDhtYgZ_OOu07Rcx3eMT62xTsJoye5XscH15lIpUG0ixs5pAukcnAXKQ5u48YSWL8xgd0oRFAEIrr0d3NjdCvtW95VwVyRbZW7WHKQC08pLJL9gk-LE0dkCzWcohQjHBXi_QgI627i-xIzfX4I0BBLLBWiDxTEguV1UJ474uwiJrBjDbJWmRZWV2myRGi7NA-ZaWdi7KDWlLhW31DUOJJOnFgYphQWIA_Wm3cO49GGMdBqt7aAoWxy3N3xjExEr-pOKyGvcee6sBQ7sDubaOjljNV_Gqp463OLpu1KcRd57Hmd80bIt9qkHvo4waU4A"
    }

    And after that when we passed this token in the application-configuration API endpoint, it still had the same response as earlier.

    image.png

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    The scope in your access_token only have openid

    Please update your code as below:

    var userClaimsPrincipalFactory = context.HttpContext.RequestServices.GetRequiredService<IUserClaimsPrincipalFactory<Volo.Abp.Identity.IdentityUser>>();
    
    var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user);
    
    //Remove
    -claimsPrincipal.SetScopes(claimsPrincipal.GetScopes());
    -claimsPrincipal.SetResources(await GetResourcesAsync(context, claimsPrincipal.GetScopes()));
    
    /Add
    +claimsPrincipal.SetScopes(request.GetScopes());
    +claimsPrincipal.SetResources(await GetResourcesAsync(context, request.GetScopes()));
    
    
    await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimsPrincipalManager>().HandleAsync(context.Request, claimsPrincipal);
    
    return new Microsoft.AspNetCore.Mvc.SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, claimsPrincipal);
    

    image.png

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
Do you need assistance from an ABP expert?
Schedule a Meeting
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v9.2.0-preview. Updated on March 13, 2025, 04:08