How do I create a ClaimsIdentity object for Asp.NET MVC 5?

不羁的心 提交于 2019-12-03 04:50:15

问题


I am working in a .NET MVC 5 application. I do not want to use Entity Framework. I want to authenticate to a RavenDB database. It looks to me that I want to replace the UserManager that comes with the Account Controller. I think I can rewrite all the UserManager functions to work with my database, except I don't understand the ClaimsIdentity object.

In the SignInAsync method, there is a call to UserManager.CreateIdentityAsync(...). I know it returns a ClaimsIdentity object. What I don't know is how to create a ClaimsIdentity object on my own.

I see that it has 4 properties Actor, BootstrapContext, Claims and Label. I don't know what these properties are used for, and I don't know how to properly generate them. I assume generating them correctly is important since it is how the authentication cookie is made.

I looked at the explanation of the ClaimsIdentity object here, but that didn't really help me understand.

If I could see the code for CreateIdentityAsync(), that would probably help.

If I'm going about this all wrong, please let me know. Otherwise, if someone could point me toward how to generate the ClaimsIdentity object, that would be helpful.

ClaimsIdentity identity = new ClaimsIdentity
{
    Actor = ????,
    BootstrapContext = ?????,
    Claims = ?????,
    Label = ?????
}

回答1:


Perhaps the following link can help:

var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, "Brock"));
claims.Add(new Claim(ClaimTypes.Email, "brockallen@gmail.com"));
var id = new ClaimsIdentity(claims,DefaultAuthenticationTypes.ApplicationCookie);

var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(id);



回答2:


I think you are "going about this all wrong". The ASP.NET Identity Framework is designed with pluggable persistence in mind. The correct way to substitute RavenDB for EF is NOT to replace the UserManager. Rather, it is to implement a replacement UserStore. So the line in the AccountController that creates the UserManager would change from:

public AccountController()
    : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))

To:

public AccountController()
    : this(new UserManager<ApplicationUser>(new RavenDBUserStore<ApplicationUser>/* connection info here*/)))

Where the RavenDBUserStore would be a class you wrote that implemented IUserStore, IUserPasswordStore and whatever other *Store interfaces you needed for your particular application.

This approach avoids you needing to understand and re-implement everything in UserManager and ensures that you will be able to take advantage of future improvements to the UserManager from MS.

For more information on how to do this, see the Overview of Custom Storage Providers for ASP.NET Identity and the example of Implementing a Custom MySQL ASP.NET Identity Storage Provider. You should also check out the code of the RavenDB.AspNet.Identity Nuget Package created by David Boike mentioned in his answer. The source is on github at https://github.com/ILMServices/RavenDB.AspNet.Identity/tree/master/RavenDB.AspNet.Identity




回答3:


Here is what I came up with. I would love to know if this is the correct way to accomplish this task.

Working in a default MVC5 website, I went to the Account Controller, and found the SignInAsync() function. I adjusted it as follows:

    private async Task SignInAsync(ApplicationUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
        //var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); --> this is where I want to get rid of UserManager
        List<Claim> claims = new List<Claim>{
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", user.Name), //user.Name from my database
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", user.Id), //user.Id from my database
            new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "MyApplication"),
            new Claim("FirstName", user.FirstName) //user.FirstName from my database
        };
        ClaimsIdentity identity = new System.Security.Claims.ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);

        AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
    }

Keep in mind that this also requires changing the [HttpPost] Login function to get the user from my database instead of using the UserManager.FindAsync() function.

The LogIn/LogOff parts of the default site seem to work fine after these adjustments. I'll leave this answer here for a while before I accept it in case someone can tell me why I shouldn't do it this way.




回答4:


I created a RavenDB implementation for the new ASP.NET MVC 5 Identity and released it as a NuGet package. This might work for you.

http://www.nuget.org/packages/RavenDB.AspNet.Identity/

It's somewhat prerelease but I am using it in a real project.

Here's the GitHub project and a short thread on the RavenDB discussion group about it.




回答5:


I hope there is no issue that i'm post a Q/A here, which does not fit in comment section

@Katstevens does it look right to you: my team mate found this solution and use it for long, so i implement it in my own application too, but since the getUserId didn't worked, i found what is in here, and then i add the claim to my custom data, on Global.aspx start method:

protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    if (authCookie != null)
    {
        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
        CustomPrincipalSerializeModel serializeModel = JsonConvert.DeserializeObject<CustomPrincipalSerializeModel>(authTicket.UserData);
        CustomPrincipal newUser = new CustomPrincipal(authTicket.Name);
        newUser.UserId = serializeModel.UserId;
        newUser.UserName = serializeModel.UserName;
        newUser.NameFamily = serializeModel.NameFamily;
        newUser.IP = serializeModel.IP;
        newUser.roles = serializeModel.roles;
        HttpContext.Current.User = newUser;
        System.Threading.Thread.CurrentPrincipal = newUser;

        //Added by myself... (make UserId work as identity.GetUserId())
        (newUser.Identity as ClaimsIdentity)?.AddClaims(new List<Claim>{
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", authTicket.Name), //user.Name from my database
            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", serializeModel.UserId), //user.Id from my database
            new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "RealEstate"), //MyApplication
        });
    }
}

Yes it works, But it it a right thing to do it like this? where should data come from, where should this happen? ETC.... are the data irreplaceable? and secure?



来源:https://stackoverflow.com/questions/20391592/how-do-i-create-a-claimsidentity-object-for-asp-net-mvc-5

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!