Jak zaktualizować oświadczenie w ASP.NET Identity?

97

Używam uwierzytelniania OWIN dla mojego projektu MVC5. To jest mójSignInAsync

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

Jak widać, dodałem AccountNodo listy roszczeń.

Jak mogę teraz zaktualizować to roszczenie w którymś momencie w mojej aplikacji? Jak dotąd mam to:

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

        }

kiedy próbuję usunąć roszczenie, otrzymuję ten wyjątek:

Nie można usunąć roszczenia „ http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata : 101”. Nie jest częścią tej Tożsamości lub jest roszczeniem, które jest własnością Zleceniodawcy i zawiera tę Tożsamość. Na przykład jednostka główna będzie właścicielem żądania podczas tworzenia GenericPrincipal z rolami. Role zostaną ujawnione za pośrednictwem tożsamości przekazanej w konstruktorze, ale nie będącej w rzeczywistości własnością Identity. Podobna logika istnieje dla RolePrincipal.

Czy ktoś mógłby mi pomóc dowiedzieć się, jak zaktualizować roszczenie?

Irshu
źródło
Jeśli przechowujesz informacje o użytkowniku w roszczeniu i chcesz zaktualizować roszczenie, po zmianie informacji o użytkowniku możesz zadzwonić: w SignInManager.SignInAsynccelu odświeżenia wartości roszczenia. Zobacz to pytanie
Hooman Bahreini,

Odpowiedzi:

126

Utworzyłem metodę rozszerzenia, aby dodać / zaktualizować / odczytać oświadczenia na podstawie danego 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;
            }
    }
}

a następnie użyć go

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");           
        }
    }
}
Frank Fu
źródło
Wreszcie. Miałem na to inne rozwiązanie i wydawało się, że działa ... głównie. Ale ostatecznie przeszedłem na tę metodę, ponieważ wydaje się, że zawsze działa. Dziękuję Ci!
saml
3
Czy ktoś ma to samo rozwiązanie dla Asp.Net One Core?
Martín
Wygląda na to, że działa tylko dla bieżącej aplikacji. Chciałbym zaktualizować plik cookie wysyłany przez serwer SSO, aby inne aplikacje również miały do ​​nich dostęp. Każdy pomysł jak? Dzięki
Ktokolwiek,
@Whoever Ponieważ plik cookie jest podpisany przez serwer SSO, aby pokazać, że nie został zmodyfikowany (a zatem można mu zaufać), byłbym zaskoczony, gdyby istniał jakikolwiek sposób na osiągnięcie tego, ponieważ byłby to manipulacja.
Mog0
2
var claim = identity.Claims.First (c => c.Type == klucz); return claim.Value; powinno być var ​​claim = identity.Claims.FirstOrDefault (c => c.Type == key); zwrot roszczenia? .Value;
liuhongbo
58

Możesz utworzyć nowy, ClaimsIdentitya następnie zaktualizować roszczenia za jego pomocą.

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 }
        );
}
Irshu
źródło
4
Możesz zaktualizować oświadczenie, ale nadal musisz wylogować użytkownika i zalogować się przy użyciu zaktualizowanej tożsamości.
user3210546
3
nie, nie wylogowuje użytkownika, po prostu aktualizujemy plik cookie użytkownika
Irshu
5
Pamiętaj, że to aktualizuje tylko tożsamość. Jeśli chcesz przechowywać te roszczenia i ładować je automatycznie na żądanie, menedżer użytkownika również musi je usunąć i zaktualizować. Zajęło mi to trochę czasu! :(
Dennis van der Stelt
3
A jeśli w ogóle nie mam plików cookie i używam tylko accessToken? W moim przypadku reklamacje są takie same na kolejnym wniosku jak przed zmianą. Jedynym sposobem na zaktualizowanie roszczeń, które mam, jest wylogowanie użytkownika i poproszenie go o ponowne zalogowanie :-(
Nozim Turakulov
1
Wygląda na to, że działa tylko dla bieżącej aplikacji. Chciałbym zaktualizować plik cookie wysyłany przez serwer SSO, aby inne aplikacje również miały do ​​nich dostęp. Każdy pomysł jak? Dzięki
Ktokolwiek,
18

Inne (asynchroniczne) podejście, wykorzystujące Identity's UserManager i SigninManager, aby odzwierciedlić zmianę w pliku cookie tożsamości (i opcjonalnie usunąć oświadczenia z tabeli bazy danych 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);
  }
}
RickL
źródło
Dla mnie wskazówka polegała na tym, aby zrobić to SignInAsync() po założeniu roszczeń.
H Dog
Dzięki za wskazówkę dotyczącą usuwania roszczeń z DB. Uświadomiłam sobie, że muszę po sobie posprzątać.
Uber Schnoz
14

Korzystając z najnowszej tożsamości Asp.Net z .net core 2.1, mogę aktualizować oświadczenia użytkowników z następującą logiką.

  1. Zarejestruj się UserClaimsPrincipalFactory, aby za każdym razem, gdy SignInManagerdołączył użytkownik, tworzone były roszczenia.

    services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimService>();
    
  2. Zaimplementuj niestandardowy sposób, UserClaimsPrincipalFactory<TUser, TRole>jak poniżej

    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. Później w aplikacji, gdy zmienisz coś w bazie danych i chcesz to odzwierciedlić dla uwierzytelnionego i zalogowanego użytkownika, następujące wiersze osiągają to:

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

Dzięki temu użytkownik może zobaczyć aktualne informacje bez konieczności ponownego logowania. Wstawiłem to tuż przed zwróceniem wyniku w sterowniku aby po zakończeniu operacji wszystko bezpiecznie odświeżyło.

Zamiast edytować istniejące roszczenia i tworzyć warunki wyścigu dla bezpiecznego pliku cookie itp., Wystarczy po cichu zalogować użytkownika i odświeżyć stan :)

Mahmut C
źródło
Dzięki, napotkałem ten sam problem i to rozwiązanie działa lepiej w przypadku aktualizacji roszczeń dla podpisanego użytkownika.
ameya
Dzięki! napotkał ten sam problem w net core 3.1
Kevin Tran
7

Ja też dostaję ten wyjątek i wyjaśniłem takie sprawy

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);
IDisposable
źródło
4

Skompilowałem kilka odpowiedzi stąd do klasy ClaimsManager wielokrotnego użytku z moimi dodatkami.

Roszczenia zostały utrwalone, plik cookie użytkownika zaktualizowany, logowanie zostało odświeżone.

Należy pamiętać, że ApplicationUser można zastąpić IdentityUser, jeśli wcześniej nie dostosowałeś. Również w moim przypadku musi mieć nieco inną logikę w środowisku programistycznym, więc możesz chcieć usunąć zależność 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>();
    }
}

}

Sasha
źródło
2

kiedy używam MVC5 i dodaję tutaj roszczenie.

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

kiedy sprawdzam wynik roszczenia w funkcji SignInAsync, i tak nie mogę uzyskać wartości roli. Ale...

po zakończeniu tego żądania mogę uzyskać dostęp do roli w innej akcji (inne żądanie).

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

więc myślę, że być może asynchroniczne powoduje aktualizację IEnumerable za procesem.

user7372976
źródło
1

Możesz zaktualizować oświadczenia dla bieżącego użytkownika, implementując CookieAuthenticationEventsklasę i zastępując ValidatePrincipal. Tam możesz usunąć stare roszczenie, dodać nowe, a następnie zastąpić głównego zobowiązanego za pomocą CookieValidatePrincipalContext.ReplacePrincipal. Nie wpływa to na żadne roszczenia przechowywane w bazie danych. To używa 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;
    }
}

Musisz zarejestrować klasę wydarzeń w Startup.cs:

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

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

Możesz wstrzyknąć usługi do klasy zdarzeń, aby uzyskać dostęp do nowej AccountNowartości, ale zgodnie z ostrzeżeniem na tej stronie należy unikać robienia niczego zbyt kosztownego:

Ostrzeżenie

Opisane tutaj podejście jest uruchamiane przy każdym żądaniu. Sprawdzanie poprawności plików cookie uwierzytelniania dla wszystkich użytkowników na każde żądanie może spowodować duży spadek wydajności aplikacji.

Simon C.
źródło
dzięki, to zadziałało świetnie w asp.net core 3.1!
darkezm0
0

Aby usunąć szczegóły roszczenia z bazy danych, możemy użyć poniższego kodu. Musimy również zalogować się ponownie, aby zaktualizować wartości plików 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");
Abdul Rahim
źródło
0

Wiele plików cookie, wiele roszczeń

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
        }
    }
OMANSAK
źródło
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));
        }
İbrahim Ayağıbüyük
źródło
7
Zwykle lepiej jest wyjaśnić rozwiązanie, zamiast po prostu publikować kilka wierszy anonimowego kodu. Możesz przeczytać Jak napisać dobrą odpowiedź , a także wyjaśnić odpowiedzi w całości oparte na kodzie
Anh Pham
0

Używam aplikacji .net core 2.2 i użyłem następującego rozwiązania: w moim statup.cs

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

stosowanie

  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 ...
              
macm
źródło
-1

Metoda rozszerzenia działała świetnie dla mnie z jednym wyjątkiem, że jeśli użytkownik się wyloguje, stare zestawy roszczeń nadal istniały, więc z niewielką modyfikacją, ponieważ przekazywanie menedżera użytkownika przez wszystko działa świetnie i nie trzeba się wylogowywać i logować. Nie mogę odpowiedzieć bezpośrednio, ponieważ moja reputacja została odrzucona :(

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


}
user1158280
źródło
-2

Proszę bardzo:

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

zaczerpnięte stąd.

RayLoveless
źródło