热巧克力认证连接用户

问题描述

我的 GraphQL 查询类中有一个非常简单的 IQueryable。我想要完成的是获取请求聊天信息的授权用户。将 context.Chats 更改为 context.Chats.Where(i => i.UserId == RequestingId)。所以你不能从我的 API 获得私人聊天。如果您未获得授权,那么您将始终收到一个空列表。我已经看到如何使用 MVC 控制器执行此操作,但这不是想要的结果。

public class Query
{
    [UseDbContext(typeof(AppDbContext))]
    [UseFiltering]
    [UseSorting]
    public IQueryable<Chat> GetChats([ScopedService] AppDbContext context)
    {
        return context.Chats
           .Include(m => m.Messages)
           .Include(r => r.Recipients);
    }
}

解决方法

[UseDbContext(typeof(AppDbContext))]
    [UseFiltering]
    [UseSorting]
    public IQueryable<Chat> GetChats([ScopedService] AppDbContext context,[Service] IHttpContextAccessor httpContextAccessor)
    {
        ClaimsPrincipal authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(JwtParser.ParseClaimsFromJwt(httpContextAccessor.HttpContext.Request.Headers["Authorization"]),Startup.JWT_AUTH_TYPE));
        int userId;
        int.TryParse(authenticatedUser.Claims.FirstOrDefault(i => i.Type.Equals(ClaimTypes.NameIdentifier))?.Value,out userId);
        return context.Chats
            .Include(m => m.Messages)
            .Include(r => r.Recipients)
            .Where(i => i.Recipients.Any(i => i.UserId == userId));
    }

将此添加到 StartUp.cs

services.AddHttpContextAccessor();

使用 JwtParser 加上

public static class JwtParser
{
    public static IEnumerable<Claim> ParseClaimsFromJwt(string jwt)
    {
        List<Claim> claims = new();
        string payload = jwt.Split('.')[1];
        byte[] jsonBytes = ParseBase64WithoutPadding(payload);
        Dictionary<string,object> keyValuePairs = JsonSerializer.Deserialize<Dictionary<string,object>>(jsonBytes);
        ExtractRolesFromJwt(claims,keyValuePairs);
        claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key,kvp.Value.ToString())));
        return claims;
    }

    private static void ExtractRolesFromJwt(List<Claim> claims,Dictionary<string,object> keyValuePairs)
    {
        keyValuePairs.TryGetValue(ClaimTypes.Role,out object roles);
        if (roles is null) return;
        string[] parsedRoles = roles.ToString().Trim().TrimStart('[').TrimEnd(']').Split(',');
        if (parsedRoles.Length > 1)
        {
            foreach (string parsedRole in parsedRoles)
            {
                claims.Add(new Claim(ClaimTypes.Role,parsedRole.Trim('"')));
            }
        }
        else
        {
            claims.Add(new Claim(ClaimTypes.Role,parsedRoles[0]));
        }
        keyValuePairs.Remove(ClaimTypes.Role);
    }

    private static byte[] ParseBase64WithoutPadding(string base64)
    {
        switch (base64.Length % 4)
        {
            case 2:
                base64 += "==";
                break;
            case 3:
                base64 += "=";
                break;
        }
        return Convert.FromBase64String(base64);
    }
}

这是我开始工作的东西。有没有更好的解决方案,或者这是否足够好?

,

您可以像下面这样注入用户的 ClaimsPrincipal

public IQueryable<Chat> GetChats([ScopedService] AppDbContext context,[GlobalState(nameof(ClaimsPrincipal))] ClaimsPrincipal claimsPrincipal)
{
    // ...
}

在即将发布的 v11.3.1 中,您还可以简单地编写:

public IQueryable<Chat> GetChats([ScopedService] AppDbContext context,ClaimsPrincipal claimsPrincipal)
{
    // ...
}

您可以像这样访问经过身份验证的用户的 ID:

var userId = claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier);

注意:声明可能会有所不同,具体取决于您设置身份验证/授权机制的方式。