C# 将主体/用户上下文设置为用户对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19643754/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 15:31:00  来源:igfitidea点击:

Set Principal/User Context to a User Object

c#authenticationasp.net-web-apiauthorization

提问by ShaneC

My WebAPI 2 application has a custom authorization filter which checks for an access token. If the token is present, and the API has the attribute, then I check if there exists a user which maps to that token.

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

Due to the nature of the API, most methods run in the context of a particular user (i.e. "POST api/profile" to update a user's profile). In order to do this, I need information on the target user which I get from the access token.

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

[Current Implementation, happens within attribute of type AuthorizeAttribute]

[当前实现,发生在 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;
}

This works fine, and I'm able to then use the access token to do a second lookup in the Method. But since I already do a lookup at auth time, I don't want to waste another DB call.

这工作正常,然后我可以使用访问令牌在方法中进行第二次查找。但是由于我已经在身份验证时间进行了查找,因此我不想浪费另一个 DB 调用

[What I'd like to do (but obviously doesn't work)]

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

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;
}

采纳答案by user1429080

You could use your own principal class. Maybe something like:

您可以使用自己的主要类。也许是这样的:

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

Then your action filter could do:

那么您的操作过滤器可以执行以下操作:

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;

And subsequently in your actual method, you can take the current user, check if it's of type MyPrincipaland if so cast it and then access the UserDetails:

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

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

I haven't actaully tried this code, so there might be typos...

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

回答by Jos Vinke

You could use a ClaimsIdentity/ClaimsPrincipaland add the Claimsyou need later in your controller, for example the actors ID or other values you need.

您可以使用 aClaimsIdentity/ClaimsPrincipalClaims在您的控制器中添加您稍后需要的,例如角色 ID 或您需要的其他值。

I've made an example which sets claims to the Actor but if it better suits you you could also at Claims directly to the current User.

我已经做了一个例子,它设置了对演员的声明,但如果它更适合你,你也可以直接对当前用户进行声明。

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;