【问题标题】:Set Principal/User Context to a User Object将主体/用户上下文设置为用户对象
【发布时间】:2013-11-07 18:05:53
【问题描述】:

我的 WebAPI 2 应用程序有一个自定义授权过滤器,用于检查访问令牌。如果令牌存在,并且 API 具有该属性,那么我检查是否存在映射到该令牌的用户。

由于 API 的性质,大多数方法在特定用户的上下文中运行(即“POST api/profile”以更新用户的个人资料)。为此,我需要从访问令牌中获得的目标用户信息。

[当前实现,发生在 AuthorizeAttribute 类型的属性中]

if( myDBContext.MyUsers.Count( x => x.TheAccessToken == clientProvidedToken ) ){
    IPrincipal principal = new GenericPrincipal( new GenericIdentity( myAccessToken ), new string[] { "myRole" } );
    Thread.CurrentPrincipal = principal;
    HttpContext.Current.User = principal;
    return true;
}

这很好用,然后我可以使用访问令牌在方法中进行第二次查找。 但由于我已经在身份验证时进行了查找,我不想浪费另一个数据库调用

[我想做的事(但显然行不通)]

MyUser user = myDBContext.MyUsers.FirstOrDefault( x => x.TheAccessToken == clientProvidedToken );
if( user != null ){
    // Set *SOME* property to the User object, such that it can be
    // access in the body of my controller method
    // (e.g. /api/profile uses this object to load data)
    HttpContext.Current.User = user;
    return true;
}

【问题讨论】:

    标签: c# authentication asp.net-web-api authorization


    【解决方案1】:

    您可以使用ClaimsIdentity/ClaimsPrincipal,然后在控制器中添加您稍后需要的Claims,例如您需要的演员 ID 或其他值。

    我已经做了一个设置对 Actor 的声明的示例,但如果它更适合您,您也可以在 Claims 中直接对当前用户进行声明。

    var identity = new ClaimsIdentity(HttpContext.Current.User.Identity);
    identity.Actor = new ClaimsIdentity();
    identity.Actor.AddClaim(new Claim("Your", "Values"));
    
    var principal = new ClaimsPrincipal(identity);
    Thread.CurrentPrincipal = principal;
    HttpContext.Current.User = Thread.CurrentPrincipal;
    

    【讨论】:

    • 使用声明更好,因为它与框架保持一致而不是与之对抗。或者,如果代码无论如何都依赖于 HttpContext 也可以使用 HttpContext.Profile 。 msdn.microsoft.com/en-us/library/…
    【解决方案2】:

    您可以使用自己的主体类。可能是这样的:

    public class MyPrincipal : GenericPrincipal
    {
        public MyPrincipal(IIdentity identity, string[] roles)
            : base(identity, roles)
        {
        }
        public MyUser UserDetails {get; set;}
    }
    

    那么你的动作过滤器可以做:

    MyUser user = myDBContext.MyUsers.FirstOrDefault( x => x.TheAccessToken == clientProvidedToken );
    if(user != null)
    {
        MyPrincipal principal = new MyPrincipal( new GenericIdentity( myAccessToken ), new string[] { "myRole" } );
        principal.UserDetails = user;
        Thread.CurrentPrincipal = principal;
        HttpContext.Current.User = principal;
        return true;
    }
    return false;
    

    随后在您的实际方法中,您可以获取当前用户,检查它是否为 MyPrincipal 类型,如果是,则对其进行转换,然后访问 UserDetails:

    ...
    MyUser currentUser = null;
    MyPrincipal curPrincipal = HttpContext.Current.User as MyPrincipal;
    if (curPrincipal != null)
    {
        currentUser = curPrincipal.UserDetails;
    }
    ...
    

    我还没有实际尝试过这段代码,所以可能有错别字...

    【讨论】:

    • 不知道为什么我没有想到扩展 GenericPrincipal ——它工作得很好!谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-18
    • 2012-05-31
    • 2012-11-29
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多