ASP.NET MVC AspNetUserClaims如何在表中读取,写入和更新数据?

时间:2017-11-03 07:48:23

标签: c# asp.net asp.net-mvc asp.net-mvc-4 claims

这是我在StackOverflow中的第一个问题:)所以请不要判断我强大:)好的。我们走了。

我是ASP.NET MVC Framework的新手,并尝试在我的网站中实现多语言。所以我将下拉语言列表添加到_LoginPartial.cshtml:

<li class="dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown">@(MEDONET.Resources.IndexTexts.Language)<b class="caret"></b></a>
    <ul class="dropdown-menu">
        <li>@Html.ActionLink("Кыргызча", "Change", "Language", new { lang = "ky" }, null)</li>
        <li>@Html.ActionLink("Русский", "Change", "Language", new { lang = "ru" }, null)</li>
        <li>@Html.ActionLink("English", "Change", "Language", new { lang = "en" }, null)</li>
        <li>@Html.ActionLink("O'zbekcha", "Change", "Language", new { lang = "uz" }, null)</li>
    </ul>
</li>

如您所见,我将选定的语言缩写传递给语言控制器的Change方法。在LanguageController中,我的代码如下所示:

public ActionResult Change(string lang)
    {
        if (lang != null)
        {
            if (User.Identity.IsAuthenticated)
            {
                //var user =  _userManager.FindByName(User.Identity.Name);
                //_userManager.AddClaim(user.Id, new Claim("Language", lang));
                //var claims = _userManager.GetClaims(user.Id);

                ////User.RemoveClaimIfExists("Language");
                ////var claims = new List<Claim>();
                ApplicationDbContext mycontext = new ApplicationDbContext();
                UserStore<ApplicationUser> mystore = new UserStore<ApplicationUser>(mycontext);
                ApplicationUserManager UserMan = new ApplicationUserManager(mystore);
                //ApplicationUser _user = UserMan.FindById(User.Identity.GetUserId());
                UserMan.AddClaim(User.Identity.GetUserId(), new Claim("Language", lang));

                //UserMan.RemoveClaim(User.Identity.GetUserId(), User.GetClaim("Language"));
                //User.AddClaim(lang);

            }
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang);
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);

            HttpCookie cookie = new HttpCookie("Language");
            cookie.Value = lang;
            Response.Cookies.Add(cookie);

            return Redirect(Request.UrlReferrer.ToString());
        }
        return Redirect(Request.UrlReferrer.ToString());
    }

正如您所注意到的,我尝试了很多不同的方法来实现该功能。经过一天的煎熬,它开始发挥作用。但我不确定我的Frankenshtain是向AspNetUserClaims表写一个Claim的最佳方法。所以这是我的第一个问题:

  

1)如何改进我的写作索赔代码?

第二个问题与第一个问题非常接近:

  

2)如何更新现有用户声明?

最后,对于我的知识水平问题显而易见的最后三分之一是:

  

3)如何阅读存储的声明?

一旦设置声明需要在下一个会话中阅读。因此我创建了Claims类,并在此处添加了

public static string GetClaimValue(this IPrincipal currentPrincipal, string key)
    {
        var identity = currentPrincipal.Identity as ClaimsIdentity;
        if (identity == null)
            return null;

        var claim = identity.Claims.FirstOrDefault(c => c.Type == key);
        return claim?.Value;
    }

代码并从AccountController的Login方法调用它:

 [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                HttpCookie cookie = new HttpCookie("Language");
                string lang = GetClaimValue("Language");
                if (lang == null) // language was not selected befor
                    lang = "ru"; 
                Response.Cookies.Add(cookie);

                Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cookie.Value);
                Thread.CurrentThread.CurrentUICulture = new CultureInfo(cookie.Value);
                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:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }

你可以猜到我总是得到俄语,而不是吉尔吉斯语,而不是吉尔吉斯语&#34; ky&#34;存储在AspNetUserClaims表中。

那就是它:)我希望这里没有太多的桌面谈话。请帮帮我!

2 个答案:

答案 0 :(得分:0)

我将跳过你的第一个问题,因为我很难回答你没有查看使用你的声明代码的所有背景。但是,对于你的其他问题:

  

2)如何更新现有用户声明?

你可以使用这样的方法:

    public static void AddUpdateClaim(this IPrincipal currentPrincipal, string key, string value)
    {
        var identity = currentPrincipal.Identity as ClaimsIdentity;
        if (identity == null)
            return;

        // check for existing claim and remove it
        var existingClaim = identity.FindFirst(key);
        if (existingClaim != null)
            identity.RemoveClaim(existingClaim);

        // add new claim
        identity.AddClaim(new Claim(key, value));
        var authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
        authenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = true });
    }

现在你可以从任何这样的控制器中使用它:

User.AddUpdateClaim("Language", "ru");
  

3)如何阅读存储的声明?

这样的事情:

    public static string GetClaimValue(this IPrincipal principal, string type)
    {
        var user = principal as ClaimsPrincipal;
        var claim = user.Claims.FirstOrDefault(x => x.Type == type);

        if (claim != null) return claim.Value;

        throw new Exception($"Claim with type {type} not set");
    }

这两种方法都是扩展方法,可以在Controller.User对象上使用。

编辑:作为对您的评论的回复,您可以通过以下方式创建声明标识:

 var ident = new ClaimsIdentity(
                new[] { 
                    new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"),               
                },
                DefaultAuthenticationTypes.ApplicationCookie);

//Add default language to claims
ident.AddClaim(new Claim("Language", "ru"));

HttpContext.GetOwinContext().Authentication.SignIn(ident);

答案 1 :(得分:0)

  

用于更新声明

// GET: Language
    public ActionResult Change(string lang)
    {
        if(lang != null)
        {

            if(User.Identity.IsAuthenticated)
            {
                var claims = new List<Claim>();

                ApplicationDbContext mycontext = new ApplicationDbContext();
                UserStore<ApplicationUser> mystore = new UserStore<ApplicationUser>(mycontext);
                ApplicationUserManager UserMan = new ApplicationUserManager(mystore);
                ApplicationUser _user = UserMan.FindById(User.Identity.GetUserId());

                var claim = _user.Claims.FirstOrDefault(c => c.ClaimType == "Language");

                if (claim != null) // User have Language claim the table 
                {
                    if (claim.ClaimValue != lang) // and chosen language doesn't match it
                    {
                        UserMan.RemoveClaim(User.Identity.GetUserId(), new Claim("Language", claim.ClaimValue));
                        UserMan.AddClaimAsync(User.Identity.GetUserId(), new Claim("Language", lang)); 
                    }
                }
                else if(claim == null)
                {
                    UserMan.AddClaimAsync(User.Identity.GetUserId(), new Claim("Language", lang));
                }

            }
            Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(lang);
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);

            HttpCookie cookie = new HttpCookie("Language");
            cookie.Value = lang;
            Response.Cookies.Add(cookie);


            return Redirect(Request.UrlReferrer.ToString());
        }
        return Redirect(Request.UrlReferrer.ToString());
    }

在此更改操作中,我实际上正在阅读声明,但如果想在登录时阅读,我会这样做:

 [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
        switch (result)
        {
            case SignInStatus.Success:
                HttpCookie cookie = new HttpCookie("Language");
                cookie.Value = "ru";
                var user = UserManager.FindByEmail(model.Email);

                    var claim = user.Claims.FirstOrDefault(c => c.ClaimType == "Language");

                    if (claim == null)
                    {
                        cookie.Value = Thread.CurrentThread.CurrentCulture.Name.ToString(); // interface language used befor logining in
                    }
                    else
                        cookie.Value = claim.ClaimValue; // Language from the UserClaim 

                Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cookie.Value);
                Thread.CurrentThread.CurrentUICulture = new CultureInfo(cookie.Value);
                Response.Cookies.Add(cookie);
                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:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }