Starts in:
2 DAYS
4 HRS
6 MIN
47 SEC
Starts in:
2 D
4 H
6 M
47 S
Open Closed

Allow Guest user to use certain application services served by a guest page #4484


User avatar
0
ten3systems created
  • ABP Framework version: v6.0.2
  • UI type: MVC
  • DB provider: EF Core
  • Tiered (MVC) or Identity Server Separated (Angular): single-layer (no-layers) template with Pro Account module

I have an app configured with roles based permissions as per the template, all works great for an actual logged in user. Now I want to have a page for anonymous users that uses certain services to get data and render to this "guest" user.

Obviously I want the app to be secure so I have devised a way that a unique URL slug is passed to the page and then verified as valid before rendering. I don't want to [AllowAnonymous] on my services obviously, but I do want this guest user with this un-guessable URL to access certain service methods after the initial page request.

I thought that I could create a Guest Role and assign the .Default permission group permissions to the role and use the identity system to mimic a logged in user in this case.

I cannot figure out how to keep utilizing the regular identity authentication system AND allow this scenario. I would even be okay with a cookie that is set on my initial request which is then used for further authorization or user authentication.

I have tried:

  • faking the HttpContext.User with a new claims principal but this does not allow AJAX service calls from my page (b/c only the page has an 'authorized' user, not the API controller)
  • using authentication middleware to detect the requested route and creating a guest principal, but in order to make that work i had to set "Cookies" as the default authentication scheme which breaks the regular authentication system

Am I going about this the wrong way? Is there a better way? How can I add a new authentication scheme to the existing project that will work alongside the regular authentication system and allow this user who makes their initial request at a specific URL an authenticated user with the system, but with my limited Guest Role?

I realize this is an advanced situation but I'm at my ropes end and am about to brute force the feature by asserting an actual user in the identity system with a Guest role but I'd rather not pollute the system and all the tenants with these needless users (note that I also may not have the guest users email address).

Any/all recommendations/insight is highly appreciated.


9 Answer(s)
  • User Avatar
    0
    gterdem created
    Senior .NET Developer

    Why not using just [Authorize] for your guest end points? So you don’t bother with permissions but just have the authentication. Or you can use AuthorizationService for some manual controls.

  • User Avatar
    0
    ten3systems created

    The guest user will not have an identity account. I want to 'fake' authorization at a landing page that only they will have the URL for. I looked at the AuthorizationService API it seems to only CHECK if the current principal is authorized, and does not seem to have any manual controls (unless I'm looking at the wrong one?)

    namespace Volo.Abp.Authorization;
    
    public interface IAbpAuthorizationService : IAuthorizationService, IServiceProviderAccessor
    
  • User Avatar
    0
    ten3systems created

    I can get middleware and a new "GuestCookies" scheme to SignInAsync my principal so that they are authorized for my single request to my landing page and theoretically that means I could set a cookie on the landing page also and use another middleware to do the same for the HttpApiControllerModule as well. I guess I was thinking that once I authorized my user they could be authorized for my service calls and be logged into the whole system but my cookie and the IdentityCookies are not the same (different scheme).

    Further complication comes from the fact that followup requests are via AJAX to the controller module which seems to be hooked up to the identity system.

    I guess the thing to do is

    1. use a new Authentication Scheme in the web project that has it's own custom handler IAuthenticationHandler, IAuthenticationSignInHandler
    2. on page load but before calling for data, .SignInAsync("CustomScheme", principal)
    3. set a custom cookie for 'auth' purposes (maybe containing my tenant id and other unique info)
    4. create a middleware for the HttpApiController module that looks for the cookie, verifies it, and authenticates it's own principal and uses the stored TenantID for data filter

    And in this way I have custom principal for my scenario, have not polluted the identity store, utilized the existing permissions system, in the correct tenant, and can still consider the 'guest' a user for all other purposes such as AuditLogs etc.

    Or I could create a single Guest user for each tenant and force sign him in on the landing page. Hahahahahasodfiiweifjaskldfjklas asfkldjfid

  • User Avatar
    0
    ten3systems created

    So overriding AbpAuthorizationService results in a call to AuthorizeAsync for an 'actually authenticated' user after the razor page (which shows CurrentUser.IsAuthenticated == true, rightly so) asks for a service method where the principal and resource are blank (but the requirements contains the permission specified in the service classes [Authorize(policyName)] attribute so the request fails. So that breaks logged in users but works for the guest user.

    If I don't override the AbpAuthorizationService then being a regular logged in user now works and I can auth my "guest" user for the page load and even though I've "signed in" subsequent calls via ajax still fails (presumably because I'm not authorizing with Identity.Application scheme, although I tried that, it did not seem to work.

    My thought now is I will have to allow the API controller a way to authorize the request separately as noted above. But perhaps with an OpenID application defined in the Administration => Open ID => Applications settings area. Then I'll have to figure out how to grab a token via that system and pass it to the JS client to use in headers of all $.AJAX requests

  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    hi

    You are making things more complicated and insecure, Please use AllowAnonymous.

  • User Avatar
    0
    ten3systems created

    You are saying to use [AllowAnonymous] on my aggregate root entities GetListAsync(GetEntityInput input) (and other aggregate entities) service calls because allowing the world to access the calls would be more secure than using an authenticated principal?

    I do not understand.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    If you need to access a method anonymously, Yes

    https://support.abp.io/QA/Questions/4484/Allow-Guest-user-to-use-certain-application-services-served-by-a-guest-page#answer-562eec34-7eec-073f-0829-3a092fd6770f

  • User Avatar
    0
    salih created
    Support Team .NET Developer

    Hi

    This suggests checking out the following resources for a solution to your issue:

    https://community.abp.io/posts/implementing-passwordless-authentication-with-asp.net-core-identity-c25l8koj https://github.com/salihozkara/Question_4484/blob/main/README.md (as an alternative if the first resource does not resolve the issue)

  • User Avatar
    0
    ten3systems created

    OMG thank-you Salih! These are highly relevant and useful answers; in this way I could authenticate against the identity system and still leverage all the roles-based-permissions systems that are integrated with the project.

    Brilliant, thank-you again. I had temporarily solved by building partial handlers that return the JSON results of the service calls I needed but obviously that is brittle and does not scale well. Your references are definitely the correct answer.

    Cheers!

Made with ❤️ on ABP v9.1.0-preview. Updated on November 20, 2024, 13:06