【问题标题】:ASP.NET MVC AspNetUserClaims How can I read, write and update data in the table?ASP.NET MVC AspNetUserClaims 如何读取、写入和更新表中的数据?
【发布时间】:2018-04-15 21:27:00
【问题描述】:

这是我在 StackOverflow 中的第一个问题 :) 所以请不要评判我强 :) 好的。我们开始吧。

我是 ASP.NET MVC 框架的新手,并试图在我的网站中实现多语言。所以我在 _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 表写入声明的最佳方式。所以这是我的第一个问题:

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

你可能猜到我总是得到俄语而不是吉尔吉斯语,它存储在 AspNetUserClaims 表中的缩写“ky”。

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

【问题讨论】:

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


    【解决方案1】:

    我将跳过您的第一个问题,因为如果不查看您使用声明代码的所有上下文,我很难回答。但是,对于您的其他问题:

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

    【讨论】:

    • 感谢您的回答!我已经尝试过这段代码,但无缘无故它不起作用。
    • 此代码 var user = currentPrincipal as ClaimsPrincipal; var claim = user.Claims.FirstOrDefault(x => x.Type == type); if (claim != null) return claim.Value;否则返回“uz”;总是返回我'uz'而不是存储在表中的'en'
    • 添加了一些额外的代码,例如。这通常用于登录方法
    • 不,兄弟,我已成功向商店添加值,但无法从那里检索它们
    • 好吧,如果您尝试再次检索它们时它们为空,那么您似乎没有成功添加这些值
    【解决方案2】:

    用于更新声明

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

    【讨论】:

      猜你喜欢
      • 2017-09-02
      • 2019-01-05
      • 1970-01-01
      • 1970-01-01
      • 2014-11-22
      • 1970-01-01
      • 1970-01-01
      • 2019-06-11
      • 1970-01-01
      相关资源
      最近更新 更多