OrchardCore icon indicating copy to clipboard operation
OrchardCore copied to clipboard

Add HttpContextExtensions

Open MikeAlhayek opened this issue 3 years ago • 1 comments

Is your feature request related to a problem? Please describe.

Currently to get info about the currently logged in like user-id we have to write code like this HttpContext.ClaimAsync(ClaimTypes.NameIdentifier) can we add extensions to the HttpContext to make the code a bit easier to work with?

Describe the solution you'd like

I think adding these extensions is helpful. If this is acceptable, I can submit a PR with this. Not sure what is the best namespace for this or where in the project this would live yet.

public static class HttpContextExtensions
{
    public static async Task<IUser> UserAsync(this HttpContext httpContext, UserManager<IUser>? userManager = null)
    {
        userManager ??= httpContext.RequestServices.GetRequiredService<UserManager<IUser>>();

        return await userManager.FindByIdAsync(await httpContext.UserIdAsync());
    }

    public static async Task<bool> AuthorizeAsync(this HttpContext httpContext, Permission permission)
    {
        if (!await httpContext.IsAuthenticatedAsync())
        {
            return false;
        }

        var _authorizationService = httpContext.RequestServices.GetRequiredService<IAuthorizationService>();

        return await _authorizationService.AuthorizeAsync(httpContext.User, permission);
    }

    public static async Task<bool> AuthorizeAsync(this HttpContext httpContext, Permission permission, object resource, IAuthorizationService? authorizationService = null)
    {
        if (!await httpContext.IsAuthenticatedAsync())
        {
            return false;
        }

        authorizationService ??= httpContext.RequestServices.GetRequiredService<IAuthorizationService>();

        return await authorizationService.AuthorizeAsync(httpContext.User, permission, resource);
    }

    public static async Task<Claim> ClaimAsync(this HttpContext httpContext, string type)
    {
        if (!await httpContext.IsAuthenticatedAsync())
        {
            throw new UnauthorizedAccessException();
        }

        return httpContext.User.FindFirst(type);
    }

    public static async Task<IEnumerable<Claim>> ClaimsAsync(this HttpContext httpContext)
    {
        if (!await httpContext.IsAuthenticatedAsync())
        {
            throw new UnauthorizedAccessException();
        }

        return httpContext.User.Claims;
    }

    public static Task<bool> IsAuthenticatedAsync(this HttpContext httpContext)
    {
        return Task.FromResult((httpContext.User?.Identity?.IsAuthenticated) ?? false);
    }

    public static async Task<T> UserAsync<T>(this HttpContext httpContext)
        where T : class, IUser
    {
        return (await httpContext.UserAsync()) as T;
    }

    public static async Task<string> UserIdAsync(this HttpContext httpContext)
    {
        var claim = await httpContext.ClaimAsync(ClaimTypes.NameIdentifier);

        return (claim?.Value) ?? httpContext.User?.Identity?.Name;
    }
}

MikeAlhayek avatar Sep 21 '22 22:09 MikeAlhayek

If I'm not we already have some extension methods to authorize the user on specific resource

hishamco avatar Sep 22 '22 07:09 hishamco

I am not a fan of adding too many methods to common objects. Either it's adding too much, or I get confused with what is standard or added by something else. Like you see httpContenxt.UserIdAsync and nothing appears when you google it. I'd rather see some kind of helpers that I invoke on purpose, like we did with the OrchardHelper.

sebastienros avatar Sep 22 '22 17:09 sebastienros

@sebastienros thanks you. PR #12478 adds these extensions as extensions for IOrchardHelper

MikeAlhayek avatar Sep 22 '22 20:09 MikeAlhayek

You can close this one.

Skrypt avatar Sep 22 '22 20:09 Skrypt