Thinktecture Identity Server v3 How do I keep claims from external providers?

I am trying to follow the simple mvcGettingStarted tutorial . Now I have implemented both GoogleAuthentication providers and FacebookAuthentication , and everything works as expected, I can really log in, and if I log in with my authentication server, I also received role requests for each user. I was wondering what if I want to keep all claims from external suppliers? A simple example. Here's what my Facebook provider setup looks like:

 var facebookOptions = new FacebookAuthenticationOptions() { AuthenticationType = "Facebook", Caption = "Sign in with Facebook", AppId = "*****", AppSecret = "****", SignInAsAuthenticationType = signInAsType, Provider = new FacebookAuthenticationProvider() { OnAuthenticated = (context) => { foreach (var x in context.User) { context.Identity.AddClaim(new Claim(x.Key, x.Value.ToString())); } return Task.FromResult(context); } }, }; facebookOptions.Scope.Add("email"); facebookOptions.Scope.Add("public_profile"); facebookOptions.Scope.Add("user_friends"); app.UseFacebookAuthentication(facebookOptions); 

In each loop, I try to save all the Facebook statements in Identity, but when I return to the SecurityTokenValidated callback, my Identity does not have them.

 app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions() { Authority = "https://localhost:44302/identity/", ClientId = "my_client", Scope = "openid profile roles email", RedirectUri = "https://localhost:44302/", ResponseType = "id_token token", SignInAsAuthenticationType = "Cookies", UseTokenLifetime = false, Notifications = new OpenIdConnectAuthenticationNotifications() { SecurityTokenValidated = async context => { //let clean up this identity //context.AuthenticationTicket.Identity doesn't have the claims added in the facebook callback var nid = new ClaimsIdentity( context.AuthenticationTicket.Identity.AuthenticationType, Constants.ClaimTypes.GivenName, Constants.ClaimTypes.Role); ........ 

Is it because I am manipulating two different names? Is there a proper way to achieve what I'm trying to do? Thanks.

+6
source share
2 answers

You would do this in your custom service implementation. By default, an application from an external provider is used. Documents in the user service: https://identityserver.imtqy.com/Documentation/docsv2/advanced/userService.html

+4
source

As @ brock-allen said, user service is the right way. So I continued and implemented a simple UserService

 public class UserService { private static InMemoryUserService _service = null; public static InMemoryUserService Get() { if(_service == null) _service = new InMemoryUserService(Users.Get()); return _service; } } 

registered my service in my factory like this

 public void Configuration(IAppBuilder app) { AntiForgeryConfig.UniqueClaimTypeIdentifier = Constants.ClaimTypes.Subject; JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>(); var factory = InMemoryFactory.Create( users: Users.Get(), clients: Clients.Get(), scopes: Scopes.Get()); factory.UserService = new Registration<IUserService>(resolver => UserService.Get()); ..... 

(Of course, that setting method is inside my launch class)

So, now I can authenticate the external user in the authentication callback of the external provider (in this case facebook), indicating all the claims I need:

 var facebookOptions = new FacebookAuthenticationOptions() { AuthenticationType = "Facebook", Caption = "Sign in with Facebook", AppId = "******", AppSecret = "*******", SignInAsAuthenticationType = signInAsType, Provider = new FacebookAuthenticationProvider() { OnAuthenticated = (context) => { foreach (var x in context.User) { context.Identity.AddClaim(new Claim(x.Key, x.Value.ToString())); } ExternalIdentity identity = new ExternalIdentity() { Claims = context.Identity.Claims, Provider = "Facebook", ProviderId = "Facebook" }; SignInMessage signInMessage = new SignInMessage(); UserService.Get().AuthenticateExternalAsync(identity, signInMessage); return Task.FromResult(context); } }, } 

Now i can do

 List<Claim> claims = await UserService.Get().GetProfileDataAsync(User as ClaimsPrincipal) as List<Claim>; 

And look that my User has all facebook requirements provided during authentication. Of course, this code is only for testing, it can be significantly improved.

+6
source

Source: https://habr.com/ru/post/981547/


All Articles