Я работаю над системой, которая использует ASP.NET MVC 5 и Identity 2 с Entity Framework 6. Когда пользователь входит в систему, я добавляю несколько утверждений к этому сеансу входа в систему. Я не хочу использовать таблицу претензий.

По одной из моих претензий мне понравилось это:

public class User : IdentityUser<int, UserLogin, UserRole, UserClaim>
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User, int> manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);

        //We add the display name so that the _LoginPartial can pick it up;
        userIdentity.AddClaim(new Claim("DisplayName", FirstName + " " + LastName));

        // Add custom user claims here
        return userIdentity;
    }
    public virtual ICollection<UserInsurance> UserInsurances { get; set; }
    public User()
    {
        UserInsurances = new List<UserInsurance>();
    }
}

И для доступа к заявке:

var claimsIdentity = User.Identity as System.Security.Claims.ClaimsIdentity;
var displayNameClaim = claimsIdentity != null
    ? claimsIdentity.Claims.SingleOrDefault(x => x.Type == "DisplayName")
    : null;
var nameToDisplay = displayNameClaim == null ? User.Identity.Name : displayNameClaim.Value;

Это хорошо работает. Но проблема в том, что мне нужно поле, которого нет в таблице User. Фактически, это одна запись в свойстве навигации пользователя (UserInsurances), и мне нужен запрос linq для доступа к ней.

var lastUserInsurance = UserInsurances.OrderByDescending(x => x.CompanyInsuranceId).First();
userIdentity.AddClaim(new Claim("CompanyInsuranceId", lastUserInsurance.CompanyInsuranceId.ToString()));

Если я помещу этот код в метод GenerateUserIdentityAsync, например «DisplayName», UserInsurances будет нулевым. Поэтому я должен добавить этот код к действию входа в систему и после успешного входа пользователя в систему. Но я попробовал, и это не сработало. Не знаю, почему, но когда я хочу получить доступ к этой заявке, ее не существует.

public virtual async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
        var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);

        switch (result)
        {
            case SignInStatus.Success:
                var user = _user.Include(x => x.UserInsurances).FirstOrDefault(x => x.NationalCode == model.UserName);
                var identity = await SignInManager.CreateUserIdentityAsync(user);
                var lastUserInsurance = user.UserInsurances.OrderByDescending(x => x.CompanyInsuranceId).FirstOrDefault();
                identity.AddClaim(new Claim("CompanyInsuranceId", lastUserInsurance.CompanyInsuranceId.ToString()));
                return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
            default:
                return View(model);
        }
    }

Может ли кто-нибудь сказать мне, почему я не могу получить доступ к этой заявке, а ее не существует? Я не знаю, как реализовать этот сценарий и получить доступ к требованию CompanyInsuranceId во всех частях моего приложения.

2
zmovahedi 20 Фев 2016 в 12:16

2 ответа

Лучший ответ

Вы должны добавить свои претензии до входа пользователя в систему. Поэтому, если по какой-либо причине вы не можете заполнить свои претензии в методе GenerateUserIdentityAsync. Просто сгенерируйте объект Identity в методе входа в систему и войдите в него. Рассмотрим этот пример:

public async Task<ActionResult> Login(LoginViewModel model,string returnUrl)
{
    var user = UserManager.Find(model.Email, model.Password);
    // now you have the user object do what you to gather claims

    if(user!=null)
    {
        var ident = UserManager.CreateIdentity(user, 
            DefaultAuthenticationTypes.ApplicationCookie);
            ident.AddClaims(new[] {
                new Claim("MyClaimName","MyClaimValue"),
                new Claim("YetAnotherClaim","YetAnotherValue"),
        });
        AuthenticationManager.SignIn(
            new AuthenticationProperties() { IsPersistent = true }, 
            ident);
        return RedirectToLocal(returnUrl);
    }
    ModelState.AddModelError("", "Invalid login attempt.");
    return View(model);
} 

Как видите, вы можете делать все, что угодно, собирать заявки и заполнять личность, а затем входить в систему.

Но если вы хотите использовать метод SignInManager.PasswordSignInAsync(), просто переопределите метод SignInManager.CreateUserIdentityAsync() таким образом, чтобы вы могли генерировать желаемые утверждения. Например, если вам нужно DbContext получить дополнительную информацию для подачи ваших заявок, вы можете просто вставить DbContext в SignInManager и использовать его в методе CreateUserIdentityAsync() следующим образом:

public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
    private readonly ApplicationDbContext _context;

    public ApplicationSignInManager(
        ApplicationUserManager userManager, 
        IAuthenticationManager authenticationManager,
        ApplicationDbContext context)
        : base(userManager, authenticationManager)
    {
        _context=context;
    }

    public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
    {
        var companyInsuranceId=_context.Users
            .Where(u=>u.NationalCode == user.UserName)
            .Select(u=>u.UserInsurances
                .OrderByDescending(x => x.CompanyInsuranceId)
                .Select(x=>x.CompanyInsuranceId)
                .FirstOrDefault())
            .FirstOrDefault();

        var ident=user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
        ident.AddClaim(new Claim("CompanyInsuranceId",
            companyInsuranceId.ToString()));
        return ident;
    }

    public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
    {
        return new ApplicationSignInManager(
            context.GetUserManager<ApplicationUserManager>(),
            context.Authentication,
            context.Get<ApplicationDbContext>());
    }
}

Теперь просто написав

var result = await SignInManager.PasswordSignInAsync(
    model.UserName, model.Password, 
    model.RememberMe, shouldLockout: false);

Вы можете войти в систему и подать дополнительные заявки.

8
Sam Farajpour Ghamari 22 Фев 2016 в 15:58

Для MVC5 дополнительные утверждения можно легко добавить через класс ApplicationUser.

Например.

    public ClaimsIdentity GenerateUserIdentity(ApplicationUserManager manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = manager.CreateIdentity(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here

        return userIdentity;
    }

Это также решает Идентификационный файл cookie теряет информацию о пользовательском заявлении после периода время

0
weng 27 Май 2017 в 10:27