问题描述
我的 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);
注意:声明可能会有所不同,具体取决于您设置身份验证/授权机制的方式。