จะอัพเดตการอ้างสิทธิ์ใน ASP.NET Identity ได้อย่างไร?


95

ฉันใช้การตรวจสอบสิทธิ์ OWIN สำหรับโครงการ MVC5 ของฉัน นี่เป็นของฉันSignInAsync

 private async Task SignInAsync(ApplicationUser user, bool isPersistent)
        {
            var AccountNo = "101";
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
            var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
            identity.AddClaim(new Claim(ClaimTypes.UserData, AccountNo));
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent, RedirectUri="Account/Index"}, identity);
        }

อย่างที่คุณเห็นฉันได้เพิ่มAccountNoเข้าไปในรายการการอ้างสิทธิ์

ตอนนี้ฉันจะอัปเดตการอ้างสิทธิ์นี้ในแอปพลิเคชันของฉันได้อย่างไร จนถึงตอนนี้ฉันมีสิ่งนี้:

 public string AccountNo
        {

            get
            {
                var CP = ClaimsPrincipal.Current.Identities.First();
                var Account= CP.Claims.FirstOrDefault(p => p.Type == ClaimTypes.UserData);
                return Account.Value;
            }
            set
            {
                var CP = ClaimsPrincipal.Current.Identities.First();
                var AccountNo= CP.Claims.FirstOrDefault(p => p.Type == ClaimTypes.UserData).Value;
                CP.RemoveClaim(new Claim(ClaimTypes.UserData,AccountNo));
                CP.AddClaim(new Claim(ClaimTypes.UserData, value));
            }

        }

เมื่อฉันพยายามลบการอ้างสิทธิ์ฉันได้รับข้อยกเว้นนี้:

การอ้างสิทธิ์ " http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata : 101" ไม่สามารถลบออกได้ มันไม่ได้เป็นส่วนหนึ่งของข้อมูลประจำตัวนี้หรือเป็นการอ้างสิทธิ์ที่เป็นของอาจารย์ใหญ่ที่มีข้อมูลประจำตัวนี้ ตัวอย่างเช่น Principal จะเป็นเจ้าของการอ้างสิทธิ์เมื่อสร้าง GenericPrincipal ที่มีบทบาท บทบาทจะถูกเปิดเผยผ่าน Identity ที่ส่งผ่านในตัวสร้าง แต่ Identity ไม่ได้เป็นเจ้าของจริงๆ มีตรรกะที่คล้ายกันสำหรับ RolePrincipal

มีใครช่วยหาวิธีอัปเดตการอ้างสิทธิ์ได้ไหม


หากคุณกำลังจัดเก็บข้อมูลผู้ใช้ในการอ้างสิทธิ์และคุณต้องการอัปเดตการอ้างสิทธิ์เมื่อข้อมูลผู้ใช้มีการเปลี่ยนแปลงคุณสามารถโทร: SignInManager.SignInAsyncเพื่อรีเฟรชค่าของการอ้างสิทธิ์ ดูคำถามนี้
Hooman Bahreini

คำตอบ:


125

ฉันสร้างวิธีการขยายเพื่อเพิ่ม / อัปเดต / อ่านการอ้างสิทธิ์ตาม ClaimsIdentity ที่กำหนด

namespace Foobar.Common.Extensions
{
    public static class Extensions
    {
            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 });
            }

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

แล้วจึงจะใช้งานได้

using Foobar.Common.Extensions;

namespace Foobar.Web.Main.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            // add/updating claims
            User.AddUpdateClaim("key1", "value1");
            User.AddUpdateClaim("key2", "value2");
            User.AddUpdateClaim("key3", "value3");
        }

        public ActionResult Details()
        {
            // reading a claim
            var key2 = User.GetClaim("key2");           
        }
    }
}

สุดท้าย. ฉันมีวิธีแก้ไขอื่นสำหรับสิ่งนี้และดูเหมือนว่าจะใช้งานได้ ... ส่วนใหญ่ แต่ในที่สุดก็เปลี่ยนมาใช้วิธีนี้เนื่องจากดูเหมือนว่าจะได้ผลเสมอ ขอบคุณ!
saml

3
ใครมีวิธีแก้ปัญหาเดียวกันสำหรับ Asp.Net One Core หรือไม่?
Martín

สิ่งนี้ดูเหมือนจะใช้ได้กับแอปพลิเคชันปัจจุบันเท่านั้น ฉันต้องการอัปเดตคุกกี้ที่ออกโดยเซิร์ฟเวอร์ SSO เพื่อให้แอปอื่น ๆ สามารถเข้าถึงได้เช่นกัน มีความคิดอย่างไร ขอบคุณ
ใครก็ได้

@ ใครก็ตามเนื่องจากคุกกี้ได้รับการลงนามโดยเซิร์ฟเวอร์ SSO เพื่อแสดงว่าคุกกี้ไม่ได้รับการดัดแปลง (และสามารถเชื่อถือได้) ฉันจะแปลกใจถ้ามีวิธีใดในการบรรลุสิ่งนี้เนื่องจากจะถูกดัดแปลง
Mog0

2
การอ้างสิทธิ์ var = identity.Claims.First (c => c.Type == key); ส่งคืน Claim.Value ควรเป็น var Claim = identity.Claims.FirstOrDefault (คีย์ c => c.Type ==); คืนเคลม?. Value;
liuhongbo

57

คุณสามารถสร้างใหม่ClaimsIdentityแล้วทำการอัปเดตการอ้างสิทธิ์ด้วยสิ่งนั้น

set {
    // get context of the authentication manager
    var authenticationManager = HttpContext.GetOwinContext().Authentication;

    // create a new identity from the old one
    var identity = new ClaimsIdentity(User.Identity);

    // update claim value
    identity.RemoveClaim(identity.FindFirst("AccountNo"));
    identity.AddClaim(new Claim("AccountNo", value));

    // tell the authentication manager to use this new identity
    authenticationManager.AuthenticationResponseGrant = 
        new AuthenticationResponseGrant(
            new ClaimsPrincipal(identity),
            new AuthenticationProperties { IsPersistent = true }
        );
}

4
คุณสามารถอัปเดตการอ้างสิทธิ์ได้ แต่ยังคงต้องล็อกผู้ใช้และเข้าด้วยข้อมูลประจำตัวที่อัปเดต
user3210546

3
ไม่มีมันไม่ได้ออกจากระบบผู้ใช้เราเพิ่งอัปเดตคุกกี้ของผู้ใช้
Irshu

5
โปรดจำไว้ว่าการอัปเดตข้อมูลประจำตัวนี้เท่านั้น หากคุณต้องการจัดเก็บการอ้างสิทธิ์เหล่านี้และโหลดโดยอัตโนมัติเมื่อมีการร้องขอคุณต้องให้ usermanager ลบและอัปเดตด้วย ขอเวลาหน่อย! :(
Dennis van der Stelt

3
จะเกิดอะไรขึ้นถ้าฉันไม่มีคุกกี้เลยและใช้ accessToken เท่านั้น? ในกรณีของฉันการอ้างสิทธิ์จะเหมือนกันในคำขอถัดไปก่อนการเปลี่ยนแปลง วิธีเดียวในการอัปเดตการอ้างสิทธิ์ที่ฉันมีคือการออกจากระบบผู้ใช้และขอให้เขาเข้าสู่ระบบอีกครั้ง :-(
Nozim Turakulov

1
สิ่งนี้ดูเหมือนจะใช้ได้กับแอปพลิเคชันปัจจุบันเท่านั้น ฉันต้องการอัปเดตคุกกี้ที่ออกโดยเซิร์ฟเวอร์ SSO เพื่อให้แอปอื่น ๆ สามารถเข้าถึงได้เช่นกัน มีความคิดอย่างไร ขอบคุณ
ใครก็ได้

18

วิธีการอื่น (async) โดยใช้ UserManager และ SigninManager ของ Identity เพื่อสะท้อนการเปลี่ยนแปลงในคุกกี้ Identity (และเพื่อเลือกที่จะลบการอ้างสิทธิ์ออกจากตารางฐานข้อมูล AspNetUserClaims):

// Get User and a claims-based identity
ApplicationUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
var Identity = new ClaimsIdentity(User.Identity);

// Remove existing claim and replace with a new value
await UserManager.RemoveClaimAsync(user.Id, Identity.FindFirst("AccountNo"));
await UserManager.AddClaimAsync(user.Id, new Claim("AccountNo", value));

// Re-Signin User to reflect the change in the Identity cookie
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);

// [optional] remove claims from claims table dbo.AspNetUserClaims, if not needed
var userClaims = UserManager.GetClaims(user.Id);
if (userClaims.Any())
{
  foreach (var item in userClaims)
  {
    UserManager.RemoveClaim(user.Id, item);
  }
}

เบาะแสที่นี่สำหรับฉันคือการทำSignInAsync() หลังจากตั้งค่าการอ้างสิทธิ์
H Dog

ขอขอบคุณสำหรับเคล็ดลับในการลบการอ้างสิทธิ์ออกจากฐานข้อมูล ทำให้ฉันรู้ว่าฉันจำเป็นต้องทำความสะอาดหลังจากตัวเอง
Uber Schnoz

13

การใช้ Asp.Net Identity ล่าสุดกับ. net core 2.1 ฉันสามารถอัปเดตการอ้างสิทธิ์ของผู้ใช้ด้วยตรรกะต่อไปนี้

  1. ลงทะเบียนUserClaimsPrincipalFactoryเพื่อให้ทุกครั้งที่SignInManagerผู้ใช้ร้องเพลงการอ้างสิทธิ์จะถูกสร้างขึ้น

    services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimService>();
    
  2. ใช้แบบกำหนดเองUserClaimsPrincipalFactory<TUser, TRole>ด้านล่าง

    public class UserClaimService : UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>
    {
        private readonly ApplicationDbContext _dbContext;
    
        public UserClaimService(ApplicationDbContext dbContext, UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
        {
            _dbContext = dbContext;
        }
    
        public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
        {
            var principal = await base.CreateAsync(user);
    
            // Get user claims from DB using dbContext
    
            // Add claims
            ((ClaimsIdentity)principal.Identity).AddClaim(new Claim("claimType", "some important claim value"));
    
            return principal;
        }
    }
    
  3. ในภายหลังในแอปพลิเคชันของคุณเมื่อคุณเปลี่ยนแปลงบางสิ่งในฐานข้อมูลและต้องการแสดงสิ่งนี้ให้กับผู้ใช้ที่ได้รับการพิสูจน์ตัวตนและลงชื่อเข้าใช้บรรทัดต่อไปนี้จะบรรลุสิ่งนี้:

    var user = await _userManager.GetUserAsync(User);
    await _signInManager.RefreshSignInAsync(user);
    

ทำให้แน่ใจว่าผู้ใช้สามารถดูข้อมูลล่าสุดได้โดยไม่ต้องเข้าสู่ระบบอีกครั้ง ฉันใส่สิ่งนี้ไว้ก่อนส่งคืนผลลัพธ์ในคอนโทรลเลอร์เพื่อให้เมื่อการดำเนินการเสร็จสิ้นทุกอย่างจะได้รับการรีเฟรชอย่างปลอดภัย

แทนที่จะแก้ไขการอ้างสิทธิ์ที่มีอยู่และสร้างเงื่อนไขการแข่งขันสำหรับคุกกี้ที่ปลอดภัยเป็นต้นคุณเพียงแค่ลงชื่อผู้ใช้ในแบบเงียบ ๆ และรีเฟรชสถานะ :)


ขอบคุณประสบปัญหาเดียวกันและวิธีนี้ใช้ได้ดีกว่าสำหรับการอัปเดตการอ้างสิทธิ์สำหรับผู้ใช้ที่ลงชื่อเข้าใช้
ameya

ขอบคุณ! ประสบปัญหาเดียวกันเช่นกันใน net core 3.1
Kevin Tran

7

ฉันได้รับข้อยกเว้นนั้นเช่นกันและเคลียร์สิ่งต่างๆเช่นนี้

var identity = User.Identity as ClaimsIdentity;
var newIdentity = new ClaimsIdentity(identity.AuthenticationType, identity.NameClaimType, identity.RoleClaimType);
newIdentity.AddClaims(identity.Claims.Where(c => false == (c.Type == claim.Type && c.Value == claim.Value)));
// the claim has been removed, you can add it with a new value now if desired
AuthenticationManager.SignOut(identity.AuthenticationType);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, newIdentity);

4

รวบรวมคำตอบบางส่วนจากที่นี่ไว้ในคลาสClaimsManager ที่ใช้ซ้ำได้พร้อมส่วนเพิ่มเติมของฉัน

ยังคงมีการอ้างสิทธิ์อยู่อัปเดตคุกกี้ของผู้ใช้ลงชื่อเข้าใช้ใหม่

โปรดทราบว่า ApplicationUser สามารถแทนที่ด้วย IdentityUser ได้หากคุณไม่ได้ปรับแต่งอดีต นอกจากนี้ในกรณีของฉันจำเป็นต้องมีตรรกะที่แตกต่างกันเล็กน้อยในสภาพแวดล้อมการพัฒนาดังนั้นคุณอาจต้องการลบการพึ่งพา IWebHostEnvironment

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using YourMvcCoreProject.Models;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Hosting;

namespace YourMvcCoreProject.Identity
{
    public class ClaimsManager
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signInManager;
        private readonly IWebHostEnvironment _env;
        private readonly ClaimsPrincipalAccessor _currentPrincipalAccessor;

        public ClaimsManager(
            ClaimsPrincipalAccessor currentPrincipalAccessor,
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager,
            IWebHostEnvironment env)
        {
            _currentPrincipalAccessor = currentPrincipalAccessor;
            _userManager = userManager;
            _signInManager = signInManager;
            _env = env;
        }

        /// <param name="refreshSignin">Sometimes (e.g. when adding multiple claims at once) it is desirable to refresh cookie only once, for the last one </param>
        public async Task AddUpdateClaim(string claimType, string claimValue, bool refreshSignin = true)
        {
            await AddClaim(
                _currentPrincipalAccessor.ClaimsPrincipal,
                claimType,
                claimValue, 
                async user =>
                {
                    await RemoveClaim(_currentPrincipalAccessor.ClaimsPrincipal, user, claimType);
                },
                refreshSignin);
        }

        public async Task AddClaim(string claimType, string claimValue, bool refreshSignin = true)
        {
            await AddClaim(_currentPrincipalAccessor.ClaimsPrincipal, claimType, claimValue, refreshSignin);
        }

        /// <summary>
        /// At certain stages of user auth there is no user yet in context but there is one to work with in client code (e.g. calling from ClaimsTransformer)
        /// that's why we have principal as param
        /// </summary>
        public async Task AddClaim(ClaimsPrincipal principal, string claimType, string claimValue, bool refreshSignin = true)
        {
            await AddClaim(
                principal,
                claimType,
                claimValue, 
                async user =>
                {
                    // allow reassignment in dev
                    if (_env.IsDevelopment()) 
                        await RemoveClaim(principal, user, claimType);

                    if (GetClaim(principal, claimType) != null)
                        throw new ClaimCantBeReassignedException(claimType);                
                },
                refreshSignin);
        }

        public async Task RemoveClaims(IEnumerable<string> claimTypes, bool refreshSignin = true)
        {
            await RemoveClaims(_currentPrincipalAccessor.ClaimsPrincipal, claimTypes, refreshSignin);
        }

        public async Task RemoveClaims(ClaimsPrincipal principal, IEnumerable<string> claimTypes, bool refreshSignin = true)
        {
            AssertAuthenticated(principal);
            foreach (var claimType in claimTypes)
            {
                await RemoveClaim(principal, claimType);
            }
            // reflect the change in the Identity cookie
            if (refreshSignin)
                await _signInManager.RefreshSignInAsync(await _userManager.GetUserAsync(principal));
        }

        public async Task RemoveClaim(string claimType, bool refreshSignin = true)
        {
            await RemoveClaim(_currentPrincipalAccessor.ClaimsPrincipal, claimType, refreshSignin);
        }

        public async Task RemoveClaim(ClaimsPrincipal principal, string claimType, bool refreshSignin = true)
        {
            AssertAuthenticated(principal);
            var user = await _userManager.GetUserAsync(principal);
            await RemoveClaim(principal, user, claimType);
            // reflect the change in the Identity cookie
            if (refreshSignin)
                await _signInManager.RefreshSignInAsync(user);
        }

        private async Task AddClaim(ClaimsPrincipal principal, string claimType, string claimValue, Func<ApplicationUser, Task> processExistingClaims, bool refreshSignin)
        {
            AssertAuthenticated(principal);
            var user = await _userManager.GetUserAsync(principal);
            await processExistingClaims(user);
            var claim = new Claim(claimType, claimValue);
            ClaimsIdentity(principal).AddClaim(claim);
            await _userManager.AddClaimAsync(user, claim);
            // reflect the change in the Identity cookie
            if (refreshSignin)
                await _signInManager.RefreshSignInAsync(user);
        }

        /// <summary>
        /// Due to bugs or as result of debug it can be more than one identity of the same type.
        /// The method removes all the claims of a given type.
        /// </summary>
        private async Task RemoveClaim(ClaimsPrincipal principal, ApplicationUser user, string claimType)
        {
            AssertAuthenticated(principal);
            var identity = ClaimsIdentity(principal);
            var claims = identity.FindAll(claimType).ToArray();
            if (claims.Length > 0)
            {
                await _userManager.RemoveClaimsAsync(user, claims);
                foreach (var c in claims)
                {
                    identity.RemoveClaim(c);
                }
            }
        }

        private static Claim GetClaim(ClaimsPrincipal principal, string claimType)
        {
            return ClaimsIdentity(principal).FindFirst(claimType);    
        }    

        /// <summary>
        /// This kind of bugs has to be found during testing phase
        /// </summary>
        private static void AssertAuthenticated(ClaimsPrincipal principal)
        {
            if (!principal.Identity.IsAuthenticated)
                throw new InvalidOperationException("User should be authenticated in order to update claims");
        }

        private static ClaimsIdentity ClaimsIdentity(ClaimsPrincipal principal)
        {
            return (ClaimsIdentity) principal.Identity;
        }
    }


    public class ClaimCantBeReassignedException : Exception
    {
        public ClaimCantBeReassignedException(string claimType) : base($"{claimType} can not be reassigned")
        {
        }
    }

public class ClaimsPrincipalAccessor
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ClaimsPrincipalAccessor(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public ClaimsPrincipal ClaimsPrincipal => _httpContextAccessor.HttpContext.User;
}

// to register dependency put this into your Startup.cs and inject ClaimsManager into Controller constructor (or other class) the in same way as you do for other dependencies    
public class Startup
{
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<ClaimsPrincipalAccessor>();
        services.AddTransient<ClaimsManager>();
    }
}

}


2

เมื่อฉันใช้ MVC5 และเพิ่มการอ้างสิทธิ์ที่นี่

public async Task<ClaimsIdentity> GenerateUserIdentityAsync(PATAUserManager manager)
    {
        // Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        // Add custom user claims here
        userIdentity.AddClaim(new Claim(ClaimTypes.Role, this.Role));

        return userIdentity;
    }

เมื่อฉันตรวจสอบผลการอ้างสิทธิ์ในฟังก์ชัน SignInAsync ฉันไม่สามารถใช้ค่าบทบาทได้อยู่ดี แต่...

หลังจากคำขอนี้เสร็จสิ้นฉันสามารถเข้าถึงบทบาทในการดำเนินการอื่น ๆ (คำขออับเรนเธอร์)

 var userWithClaims = (ClaimsPrincipal)User;
        Claim CRole = userWithClaims.Claims.First(c => c.Type == ClaimTypes.Role);

ดังนั้นฉันคิดว่าอาจจะไม่ตรงกันทำให้ IEnumerable อัปเดตหลังกระบวนการ


1

คุณสามารถปรับปรุงการเรียกร้องสำหรับผู้ใช้ปัจจุบันโดยการใช้การเรียนและการเอาชนะCookieAuthenticationEvents มีคุณสามารถลบการเรียกร้องเก่าเพิ่มใหม่แล้วแทนที่เงินต้นใช้ValidatePrincipal CookieValidatePrincipalContext.ReplacePrincipalสิ่งนี้ไม่มีผลต่อการอ้างสิทธิ์ใด ๆ ที่เก็บไว้ในฐานข้อมูล นี่คือการใช้ ASP.NET Core Identity 2.2

public class MyCookieAuthenticationEvents : CookieAuthenticationEvents
{
    string newAccountNo = "102";

    public override Task ValidatePrincipal(CookieValidatePrincipalContext context)
    {
        // first remove the old claim
        var claim = context.Principal.FindFirst(ClaimTypes.UserData);
        if (claim != null)
        {
            ((ClaimsIdentity)context.Principal.Identity).RemoveClaim(claim);
        }

        // add the new claim
        ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim(ClaimTypes.UserData, newAccountNo));

        // replace the claims
        context.ReplacePrincipal(context.Principal);
        context.ShouldRenew = true;

        return Task.CompletedTask;
    }
}

คุณต้องลงทะเบียนคลาสกิจกรรมในStartup.cs:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddScoped<MyCookieAuthenticationEvents>();

    services.ConfigureApplicationCookie(o =>
    {
        o.EventsType = typeof(MyCookieAuthenticationEvents);
    });
}

คุณสามารถฉีดบริการลงในคลาสเหตุการณ์เพื่อเข้าถึงAccountNoค่าใหม่ได้แต่ตามคำเตือนในหน้านี้คุณควรหลีกเลี่ยงการทำอะไรที่แพงเกินไป:

คำเตือน

วิธีการที่อธิบายไว้ที่นี่ถูกเรียกใช้ในทุกคำขอ การตรวจสอบความถูกต้องของคุกกี้การตรวจสอบสิทธิ์สำหรับผู้ใช้ทุกคนในทุกคำขออาจส่งผลให้เกิดการลงโทษด้านประสิทธิภาพอย่างมากสำหรับแอป


ขอบคุณสิ่งนี้ใช้งานได้ดีสำหรับฉันใน asp.net core 3.1!
darkezm0

0

ในการลบรายละเอียดการอ้างสิทธิ์ออกจากฐานข้อมูลเราสามารถใช้รหัสด้านล่าง นอกจากนี้เราต้องลงชื่อเข้าใช้อีกครั้งเพื่ออัปเดตค่าคุกกี้

 // create a new identity 
            var identity = new ClaimsIdentity(User.Identity);

            // Remove the existing claim value of current user from database
            if(identity.FindFirst("NameOfUser")!=null)
                await UserManager.RemoveClaimAsync(applicationUser.Id, identity.FindFirst("NameOfUser"));

            // Update customized claim 
            await UserManager.AddClaimAsync(applicationUser.Id, new Claim("NameOfUser", applicationUser.Name));

            // the claim has been updates, We need to change the cookie value for getting the updated claim
            AuthenticationManager.SignOut(identity.AuthenticationType);
            await SignInManager.SignInAsync(Userprofile, isPersistent: false, rememberBrowser: false);

            return RedirectToAction("Index", "Home");

0

คุกกี้หลายรายการการอ้างสิทธิ์หลายรายการ

public class ClaimsCookie
    {
        private readonly ClaimsPrincipal _user;
        private readonly HttpContext _httpContext;
        public ClaimsCookie(ClaimsPrincipal user, HttpContext httpContext = null)
        {
            _user = user;
            _httpContext = httpContext;
        }

        public string GetValue(CookieName cookieName, KeyName keyName)
        {
            var principal = _user as ClaimsPrincipal;
            var cp = principal.Identities.First(i => i.AuthenticationType == ((CookieName)cookieName).ToString());
            return cp.FindFirst(((KeyName)keyName).ToString()).Value;
        }
        public async void SetValue(CookieName cookieName, KeyName[] keyName, string[] value)
        {
            if (keyName.Length != value.Length)
            {
                return;
            }
            var principal = _user as ClaimsPrincipal;
            var cp = principal.Identities.First(i => i.AuthenticationType == ((CookieName)cookieName).ToString());
            for (int i = 0; i < keyName.Length; i++)
            {
                if (cp.FindFirst(((KeyName)keyName[i]).ToString()) != null)
                {
                    cp.RemoveClaim(cp.FindFirst(((KeyName)keyName[i]).ToString()));
                    cp.AddClaim(new Claim(((KeyName)keyName[i]).ToString(), value[i]));
                }

            }
            await _httpContext.SignOutAsync(CookieName.UserProfilCookie.ToString());
            await _httpContext.SignInAsync(CookieName.UserProfilCookie.ToString(), new ClaimsPrincipal(cp),
                new AuthenticationProperties
                {
                    IsPersistent = bool.Parse(cp.FindFirst(KeyName.IsPersistent.ToString()).Value),
                    AllowRefresh = true
                });
        }
        public enum CookieName
        {
            CompanyUserProfilCookie = 0, UserProfilCookie = 1, AdminPanelCookie = 2
        }
        public enum KeyName
        {
            Id, Name, Surname, Image, IsPersistent
        }
    }

0
    if (HttpContext.User.Identity is ClaimsIdentity identity)
        {
            identity.RemoveClaim(identity.FindFirst("userId"));
            identity.AddClaim(new Claim("userId", userInfo?.id.ToString()));
            await HttpContext.SignInAsync(
                CookieAuthenticationDefaults.AuthenticationScheme,
                new ClaimsPrincipal(HttpContext.User.Identity));
        }

7
โดยปกติแล้วการอธิบายวิธีแก้ปัญหาจะดีกว่าแทนที่จะโพสต์โค้ดที่ไม่ระบุตัวตนบางแถว คุณสามารถอ่านฉันจะเขียนคำตอบที่ดีได้อย่างไรและยังอธิบายคำตอบที่ใช้รหัสทั้งหมดได้
Anh Pham

0

ฉันใช้แอพ. net core 2.2 และใช้วิธีแก้ปัญหาต่อไปนี้: ใน statup.cs ของฉัน

public void ConfigureServices(IServiceCollection services)
        {
        ...
           services.AddIdentity<IdentityUser, IdentityRole>(options =>
               {
                  ...
               })
               .AddEntityFrameworkStores<AdminDbContext>()
               .AddDefaultTokenProviders()
               .AddSignInManager();

การใช้งาน

  private readonly SignInManager<IdentityUser> _signInManager;


        public YourController(
                                    ...,
SignInManager<IdentityUser> signInManager)
        {
           ...
            _signInManager = signInManager;
        }

 public async Task<IActionResult> YourMethod() // <-NOTE IT IS ASYNC
        {
                var user = _userManager.FindByNameAsync(User.Identity.Name).Result;
                var claimToUse = ClaimsHelpers.CreateClaim(ClaimTypes.ActiveCompany, JsonConvert.SerializeObject(cc));
                var claimToRemove = _userManager.GetClaimsAsync(user).Result
                    .FirstOrDefault(x => x.Type == ClaimTypes.ActiveCompany.ToString());
                if (claimToRemove != null)
                {
                    var result = _userManager.ReplaceClaimAsync(user, claimToRemove, claimToUse).Result;
                    await _signInManager.RefreshSignInAsync(user); //<--- THIS
                }
                else ...
              

-1

วิธีการขยายใช้งานได้ดีสำหรับฉันโดยมีข้อยกเว้นประการหนึ่งคือหากผู้ใช้ออกจากระบบชุดการอ้างสิทธิ์เก่ายังคงมีอยู่ดังนั้นด้วยการปรับเปลี่ยนเล็กน้อยเช่นเดียวกับการส่ง usermanager ผ่านทุกอย่างทำงานได้ดีและคุณไม่จำเป็นต้องออกจากระบบและเข้าสู่ระบบ ฉันไม่สามารถตอบได้โดยตรงเนื่องจากชื่อเสียงของฉันถูกทำลาย :(

public static class ClaimExtensions
{
    public static void AddUpdateClaim(this IPrincipal currentPrincipal,    string key, string value, ApplicationUserManager userManager)
    {
        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)
        {
            RemoveClaim(currentPrincipal, key, userManager);
        }

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

    }

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

        // check for existing claim and remove it
        var existingClaims = identity.FindAll(key);
        existingClaims.ForEach(c=> identity.RemoveClaim(c));

        //remove old claims from store
        var user = userManager.FindById(identity.GetUserId());
        var claims =  userManager.GetClaims(user.Id);
        claims.Where(x => x.Type == key).ToList().ForEach(c => userManager.RemoveClaim(user.Id, c));

    }

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

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

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

        var claims = userManager.GetClaims(identity.GetUserId());
        var userClaims = new StringBuilder();
        claims.ForEach(c => userClaims.AppendLine($"<li>{c.Type}, {c.Value}</li>"));
        return userClaims.ToString();
    }


}

-2

ได้แล้ว:

            var user = User as ClaimsPrincipal;
            var identity = user.Identity as ClaimsIdentity;
            var claim = (from c in user.Claims
                         where c.Type == ClaimTypes.UserData
                         select c).Single();
            identity.RemoveClaim(claim);

นำมาจากที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.