Bagaimana cara memperbarui klaim di ASP.NET Identity?


95

Saya menggunakan otentikasi OWIN untuk proyek MVC5 saya. Ini milikkuSignInAsync

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

Seperti yang Anda lihat, saya menambahkan AccountNoke dalam daftar Klaim.

Sekarang, bagaimana saya dapat memperbarui Klaim ini di beberapa titik dalam aplikasi saya? Sejauh ini, saya punya ini:

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

        }

ketika saya mencoba untuk menghapus klaim, saya mendapatkan pengecualian ini:

Klaim ' http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata : 101' tidak dapat dihapus. Ini bukan merupakan bagian dari Identitas ini atau merupakan klaim yang dimiliki oleh Prinsipal yang mengandung Identitas ini. Misalnya, Prinsipal akan memiliki klaim saat membuat GenericPrincipal dengan peran. Peran akan diekspos melalui Identitas yang diteruskan dalam konstruktor, tetapi sebenarnya tidak dimiliki oleh Identitas. Logika serupa ada untuk RolePrincipal.

Bisakah seseorang membantu saya mencari cara untuk memperbarui Klaim?


Jika Anda menyimpan Info Pengguna dalam Klaim dan Anda ingin memperbarui Klaim, setelah Info Pengguna berubah, Anda dapat menghubungi: SignInManager.SignInAsyncuntuk menyegarkan nilai Klaim. Lihat pertanyaan ini
Hooman Bahreini

Jawaban:


125

Saya membuat metode Ekstensi untuk Menambahkan / Memperbarui / Membaca Klaim berdasarkan ClaimsIdentity yang diberikan

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

dan kemudian menggunakannya

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

Akhirnya. Saya punya solusi lain untuk ini dan tampaknya berhasil ... sebagian besar. Tetapi akhirnya beralih ke metode ini karena tampaknya selalu berfungsi. Terima kasih!
saml

3
Ada yang punya solusi yang sama untuk Asp.Net One Core?
Martín

Ini tampaknya hanya berfungsi untuk aplikasi saat ini. Saya ingin memperbarui cookie yang dikeluarkan oleh server SSO sehingga aplikasi lain juga dapat mengaksesnya. Tahu bagaimana caranya? Terima kasih
Siapapun

@Siapa pun Karena cookie ditandatangani oleh server SSO untuk menunjukkan bahwa itu belum dirusak (dan dengan demikian dapat dipercaya), saya akan terkejut jika ada cara untuk mencapai ini karena itu akan merusak.
Mog0

2
var claim = identity.Claims.First (c => c.Type == key); return claim.Value; harus var claim = identity.Claims.FirstOrDefault (c => c.Type == key); klaim pengembalian?. Nilai;
liuhongbo

57

Anda dapat membuat yang baru ClaimsIdentitydan kemudian melakukan pembaruan klaim dengan itu.

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
Anda dapat memperbarui klaim tetapi masih harus mengeluarkan pengguna dan masuk dengan identitas yang diperbarui.
pengguna3210546

3
tidak, itu tidak mengeluarkan pengguna, kami hanya memperbarui cookie pengguna
Irshu

5
Ingatlah bahwa ini hanya memperbarui identitas. Jika Anda ingin menyimpan klaim ini dan memuatnya secara otomatis berdasarkan permintaan, Anda perlu pengelola pengguna untuk menghapus dan memperbaruinya juga. Butuh waktu lama! :(
Dennis van der Stelt

3
Bagaimana jika saya tidak memiliki cookie sama sekali dan hanya menggunakan accessToken? Dalam kasus saya, klaim pada permintaan berikutnya sama seperti sebelum perubahan. Satu-satunya cara untuk memperbarui klaim yang saya miliki adalah dengan mengeluarkan pengguna dan memintanya untuk masuk sekali lagi :-(
Nozim Turakulov

1
Ini tampaknya hanya berfungsi untuk aplikasi saat ini. Saya ingin memperbarui cookie yang dikeluarkan oleh server SSO sehingga aplikasi lain juga dapat mengaksesnya. Tahu bagaimana caranya? Terima kasih
Siapapun

18

Pendekatan (async) lainnya, menggunakan Identity's UserManager dan SigninManager untuk mencerminkan perubahan dalam cookie Identity (dan secara opsional menghapus klaim dari tabel db 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);
  }
}

Petunjuk di sini, bagi saya, adalah melakukan hal SignInAsync() setelah menyiapkan Klaim.
H Dog

Terima kasih atas tip untuk menghapus klaim dari DB. Membuat saya sadar bahwa saya perlu membersihkan diri sendiri.
Uber Schnoz

13

Menggunakan Identitas Asp.Net terbaru dengan .net core 2.1, saya dapat memperbarui klaim pengguna dengan logika berikut.

  1. Daftarkan a UserClaimsPrincipalFactorysehingga setiap kali SignInManagerpengguna masuk, klaim dibuat.

    services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimService>();
    
  2. Terapkan kebiasaan UserClaimsPrincipalFactory<TUser, TRole>seperti di bawah ini

    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. Nanti di aplikasi Anda ketika Anda mengubah sesuatu di DB dan ingin mencerminkan ini ke pengguna yang diautentikasi dan masuk, baris berikut mencapai ini:

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

Ini memastikan pengguna dapat melihat informasi terkini tanpa perlu login lagi. Saya meletakkan ini tepat sebelum mengembalikan hasil ke pengontrol sehingga ketika operasi selesai, semuanya disegarkan dengan aman.

Alih-alih mengedit klaim yang ada dan membuat ketentuan balapan untuk cookie aman, dll., Anda cukup memasukkan pengguna secara diam-diam dan menyegarkan status :)


Terima kasih, menghadapi masalah yang sama dan solusi ini berfungsi lebih baik untuk memperbarui klaim untuk pengguna yang ditandatangani.
ameya

Terima kasih! menghadapi masalah yang sama juga di inti bersih 3.1
Kevin Tran

7

Saya mendapatkan pengecualian itu juga dan membereskan hal-hal seperti ini

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

Menyusun beberapa jawaban dari sini menjadi kelas ClaimsManager yang dapat digunakan kembali dengan tambahan saya.

Klaim dipertahankan, cookie pengguna diperbarui, proses masuk disegarkan.

Harap dicatat bahwa ApplicationUser dapat diganti dengan IdentityUser jika Anda tidak menyesuaikan sebelumnya. Juga dalam kasus saya itu perlu memiliki logika yang sedikit berbeda dalam lingkungan Pengembangan, jadi Anda mungkin ingin menghapus ketergantungan 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

saat saya menggunakan MVC5, dan menambahkan klaim di sini.

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

ketika saya memeriksa hasil klaim di fungsi SignInAsync, saya tetap tidak bisa mendapatkan nilai peran yang digunakan. Tapi...

setelah permintaan ini selesai, saya dapat mengakses Peran dalam tindakan lain (permintaan lain).

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

jadi, saya pikir mungkin asynchronous menyebabkan IEnumerable diperbarui di belakang proses tersebut.


1

Anda dapat memperbarui klaim untuk pengguna saat ini dengan menerapkan CookieAuthenticationEventskelas dan mengganti ValidatePrincipal. Di sana Anda dapat menghapus klaim lama, menambahkan yang baru, dan kemudian mengganti prinsipal menggunakan CookieValidatePrincipalContext.ReplacePrincipal. Ini tidak memengaruhi klaim apa pun yang disimpan dalam database. Ini menggunakan 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;
    }
}

Anda perlu mendaftarkan kelas acara di Startup.cs:

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

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

Anda dapat memasukkan layanan ke dalam kelas peristiwa untuk mengakses nilai baru AccountNotetapi sesuai peringatan di halaman ini, Anda harus menghindari melakukan sesuatu yang terlalu mahal:

Peringatan

Pendekatan yang dijelaskan di sini dipicu pada setiap permintaan. Memvalidasi cookie otentikasi untuk semua pengguna pada setiap permintaan dapat mengakibatkan penalti performa yang besar untuk aplikasi.


terima kasih, ini bekerja sangat baik untuk saya di asp.net core 3.1!
darkezm0

0

Untuk menghapus detail klaim dari database kita dapat menggunakan kode di bawah ini. Selain itu, kami perlu masuk lagi untuk memperbarui nilai cookie

 // 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

Beberapa Cookie, Banyak Klaim

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
Biasanya lebih baik menjelaskan solusi daripada hanya memposting beberapa baris kode anonim. Anda dapat membaca Bagaimana cara menulis jawaban yang baik , dan juga Menjelaskan sepenuhnya jawaban berbasis kode
Anh Pham

0

Saya menggunakan aplikasi .net core 2.2 dan menggunakan solusi berikut: di statup.cs saya

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

pemakaian

  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

Metode ekstensi bekerja sangat baik untuk saya dengan satu pengecualian bahwa jika pengguna logout di sana, kumpulan klaim lama masih ada, jadi dengan sedikit modifikasi seperti melewatkan usermanager melalui semuanya berfungsi dengan baik dan Anda tidak perlu logout dan login. Saya tidak bisa menjawab secara langsung karena reputasi saya telah dibenci :(

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

Ini dia:

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

diambil dari sini.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.