C#ASP.NET:如何为每种方法自动解码我的承载令牌?

问题描述 投票:0回答:2

我有一个使用承载令牌进行身份验证和授权的Web API。令牌的存在表示用户已通过身份验证;该令牌中的声明指定用户具有的授权。

我编写了一个OAuth类,用于在用户登录时查询数据库以确定用户的权限。所有这一切都很好。

现在,对于每个控制器中的每个方法,我需要从持有者令牌的声明中提取信息。我现在所做的是从令牌中定义一个包含我需要的实体的类,并编写一个静态方法从控制器方法中获取User对象,并生成包含令牌数据的类的实例:

// Bearer token class
class TokenData 
{
    public string UserId { get; set; }
    public int GroupId { get; set; }
    public string UserTag { get; set; }
    // ... more properties as needed
}

// Method to get bearer token data from user object
internal static TokenData getTokenDataFromUserPrincipal(System.Security.Principal.IPrincipal p)
{
    var identity = (ClaimsIdentity)p.Identity;
    IEnumerable<Claim> claims = identity.Claims;

    var enumerable = claims as Claim[] ?? claims.ToArray();
    var claimTypes = from x in enumerable select x.Type;

    var types = claimTypes as string[] ?? claimTypes.ToArray();
    if (!types.Contains("userId")) return null; // if a token was given but it has no UserID it's not valid.

    var claimsByType = enumerable.ToDictionary(x => x.Type, x => x.Value);

    TokenData td = new TokenData
    {
        UserId = claimsByType["userId"],
        GroupId = types.Contains("groupId") ? int.Parse(claimsByType["groupId"]) : 0,
        UserTag = types.Contains("userTag") ? claimsByType["userTag"]) : null,
        // more properies as needed
    };
    return td;
}

// A controller method that uses the claims
public HttpResponseMessage DoSomething() 
{
    TokenData td = getTokenDataFromUserPrincipal(User);
    // Now I can access the token data in the td variable.
    return Request.CreateResponse(td.UserId);
}

好的,所以这一切都很完美。我正在寻找的是,如果有一种方法可以在调用控制器方法时自动从User对象中提取声明。

Web API架构基本上已经使用User对象本身 - 它包含作为与用户相关的请求的一部分的任何信息。 (类似于Request对象,它包含所有HTTP请求数据。)

我希望能够做的是,而不是在每个控制器的开头调用getTokenDataFromUserPrincipal,而是只有一个类似于Web API的静态变量 - 例如TokenData。例如:

// A controller method that uses the claims and doesn't have to explicitly retrieve them.
public HttpResponseMessage DoSomething() 
{
    return Request.CreateResponse(TokenData.UserId);
}

我知道如何使用属性 - 我实际上编写了自定义属性,它们提取相同的令牌数据并使用它来确定用户是否可以访问某个类的函数 - 例如,我可以在我的控制器方法前面包含[MinimumUserLevel(2)]。但是必须为每个方法添加属性只会将问题移出方法之外。

总结:是否可以在请求级别设置另一个静态变量,用户代码可以按请求填充而无需将代码复制到每个控制器方法的开头?

理想情况下,有一种方法可以在管道中插入一个函数,这样在运行控制器方法之前,我可以运行代码从主体获取令牌数据,因此在控制器方法运行时它就会准备就绪。 (请注意,如果数据不存在,则拉取令牌数据的方法只返回n​​ull - 这是在没有令牌的调用实例中此静态变量的预期行为。)

c# asp.net-web-api oauth
2个回答
0
投票

您可以手动验证jwt令牌。或者将JwtBearerAuthentication添加到Owin堆栈。

Here是发现的样本之一。这将解析每个请求的令牌并设置每个请求的用户属性。

您必须为创建jwt令牌时使用的秘密进行设置。

提供的示例验证并将JWT令牌转换为在每个请求上设置的ClaimsIdentity,并且可以通过每个控制器中的User.Identity属性访问。不需要自定义代码。

由于这个软件包是由Microsoft提供的,它可能比一些自制的JWT解析器更好。

(User.Identity as ClaimsIdentity).FindFirst("userId")?.Value访问您的用户ID。

您还可以使用以下代码扩展IIdentity。

public static class IIdentityExtensions
{
    public static string UserId(this IIdentity identity)
    {
        return identity.GetClaimValue("userId");
    }

    public static string GetClaimValue(this IIdentity identity, string claimType)
    {
        return identity
            .AsClaimsIdentity()
            .Claims.FirstOrDefault(c => c.Type == claimType)?.Value;
    }

    private static ClaimsIdentity AsClaimsIdentity(this IIdentity identity)
    {
        if (!(identity?.IsAuthenticated ?? false))
            throw new UnauthorizedAccessException("User not logged-in");

        return identity as ClaimsIdentity;
    }
}

然后访问用户ID,如User.Identity.UserId()


0
投票

对此的解决方案比我做的更简单:定义ApiController的子类。

所以我只写了一个看起来像这样的类:

public class MyApiController : ApiController 
{
    // Makes token data available to any method on a class deriving from MyApiController
    public TokenData Token { get; set; }

    // Override constructor - parse token whenever instance is created
    public MyApiController() 
    {
        // Extract the token data from the User variable (User is pulled in from the base ApiController)
        Token = getTokenDataFromUserPrincipal(User);
    }

    private static TokenData getTokenDataFromUserPrincipal(System.Security.Principal.IPrincipal p)
    {
        ...
    }
}

现在我的所有控制器都来自MyApiController,而不是来自ApiController。从那时起,我就可以在任何控制器的逻辑中访问Token变量,该逻辑将包含已解析的令牌数据。

© www.soinside.com 2019 - 2024. All rights reserved.