OrchardCMS / OrchardCore

Orchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.
https://orchardcore.net
BSD 3-Clause "New" or "Revised" License
7.36k stars 2.37k forks source link

Update UserInfoController to support returning custom user claims #6263

Open vitalybrandes opened 4 years ago

vitalybrandes commented 4 years ago

How to extend OPEN ID claims to my own? I did extend user profile for some my fields as AND and i would like to claim this via OPEN ID infouser.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/jersiovic"><img src="https://avatars.githubusercontent.com/u/4950766?v=4" />jersiovic</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>You can replace default IUserClaimsPrincipalFactory by your own one on startup. Like this:</p> <pre><code>var orchardUserClaimsFactory = serviceCollection.FirstOrDefault(sd => sd.ServiceType == typeof(IUserClaimsPrincipalFactory<CoreUsers.IUser>)); if (orchardUserClaimsFactory != null) { serviceCollection.Remove(orchardUserClaimsFactory); } serviceCollection.AddScoped<IUserClaimsPrincipalFactory<CoreUsers.IUser>, YourUserClaimsFactory>();</code></pre> <p>YourUserClaimsFactory can inherit from the former one: DefaultUserClaimsPrincipalFactory.</p> <p>Then your override GenerateClaimsAsync like this:</p> <pre><code>protected override async Task<ClaimsIdentity> GenerateClaimsAsync(IUser user) { var claims = await base.GenerateClaimsAsync(user); var userProfile = (user as User).As<UserProfile>(); claims.AddClaim(new Claim("yourClaimKey", "yourValue")); }</code></pre> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/vitalybrandes"><img src="https://avatars.githubusercontent.com/u/61165619?v=4" />vitalybrandes</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <blockquote> <pre><code> var userProfile = (user as User).As<UserProfile>();</code></pre> </blockquote> <p>Did it exactly the same using claim demo from DEMO MODULE, but when i add some new claim, </p> <pre><code> if (!string.IsNullOrEmpty(userProfile.Company)) { claims.AddClaim(new Claim("company", userProfile.Company)); }</code></pre> <p>dont see the data in postman. Feeling that i missing something.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/jersiovic"><img src="https://avatars.githubusercontent.com/u/4950766?v=4" />jersiovic</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>When you say you don't see data in postman, do you mean you configured open id to server JWT Tokens instead of encrypted ones, and you decode the returned token and it doesn't contain the added claim? </p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/vitalybrandes"><img src="https://avatars.githubusercontent.com/u/61165619?v=4" />vitalybrandes</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <blockquote> <p>When you say you don't see data in postman, do you mean you configured open id to server JWT Tokens instead of encrypted ones, and you decode the returned token and it doesn't contain the added claim?</p> </blockquote> <p>Exactly! I do receive other info as username , email , full name etc, but my own claims (Company name) Not.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/jersiovic"><img src="https://avatars.githubusercontent.com/u/4950766?v=4" />jersiovic</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>It sounds weird. I imagine that you checked YourUserClaimsFactory code is called putting a breakpoint there, isn't it? Can you provide a simple example based on RC myget packages on a public github repo that shows the behavior you describe?</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/vitalybrandes"><img src="https://avatars.githubusercontent.com/u/61165619?v=4" />vitalybrandes</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <blockquote> <p>It sounds weird. I imagine that you checked YourUserClaimsFactory code is called putting a breakpoint there, isn't it? Can you provide a simple example based on RC myget packages on a public github repo that shows the behavior you describe?</p> </blockquote> <p>Unfortunately not, this is commercial product, here is my CliamPrincipalsFactory,cs</p> <p>` internal class UserClaimsPrincipalFactory : DefaultUserClaimsPrincipalFactory { public UserClaimsPrincipalFactory(UserManager<IUser> userManager, RoleManager<IRole> roleManager, IOptions<IdentityOptions> identityOptions) : base(userManager, roleManager, identityOptions) {</p> <pre><code> } protected override async Task<ClaimsIdentity> GenerateClaimsAsync(IUser user) { var claims = await base.GenerateClaimsAsync(user); var userProfile = (user as User).As<ExtendUserProfile>(); claims.AddClaim(new Claim("preferred_username", user.UserName)); var name = ""; if (!string.IsNullOrEmpty(userProfile.FirstName)) { claims.AddClaim(new Claim("given_name", userProfile.FirstName)); name += userProfile.FirstName; } if (!string.IsNullOrEmpty(userProfile.LastName)) { claims.AddClaim(new Claim("family_name", userProfile.LastName)); name += $" {userProfile.LastName}"; } if (!string.IsNullOrEmpty(name)) claims.AddClaim(new Claim("name", name)); if (!string.IsNullOrEmpty(userProfile.Company)) { claims.AddClaim(new Claim("company", userProfile.Company)); } if (userProfile.UpdatedAt != default) claims.AddClaim(new Claim("updated_at", ConvertToUnixTimestamp(userProfile.UpdatedAt).ToString(CultureInfo.InvariantCulture))); return claims; }</code></pre> <p>`</p> <p>Everything except "Company" works</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/vitalybrandes"><img src="https://avatars.githubusercontent.com/u/61165619?v=4" />vitalybrandes</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>I test it again and what actually happen is that AddClaim was successfully done, but once i am authenticating via /connect/userinfo (WPF Desktop app) i am receive everything except "company"</p> <p>The "Company" filed is additional field for User Profile</p> <p>@kevinchalet Do you know why that can be?</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/kevinchalet"><img src="https://avatars.githubusercontent.com/u/6998306?v=4" />kevinchalet</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>The userinfo endpoint only returns a limited predefined set, so your custom claims are simply ignored: <a href="https://github.com/OrchardCMS/OrchardCore/blob/dev/src/OrchardCore.Modules/OrchardCore.OpenId/Controllers/UserInfoController.cs">https://github.com/OrchardCMS/OrchardCore/blob/dev/src/OrchardCore.Modules/OrchardCore.OpenId/Controllers/UserInfoController.cs</a></p> <p>There's currently no hook to allow you to return custom claims from the default userinfo action.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/vitalybrandes"><img src="https://avatars.githubusercontent.com/u/61165619?v=4" />vitalybrandes</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <blockquote> <p>The userinfo endpoint only returns a limited predefined set, so your custom claims are simply ignored: <a href="https://github.com/OrchardCMS/OrchardCore/blob/dev/src/OrchardCore.Modules/OrchardCore.OpenId/Controllers/UserInfoController.cs">https://github.com/OrchardCMS/OrchardCore/blob/dev/src/OrchardCore.Modules/OrchardCore.OpenId/Controllers/UserInfoController.cs</a></p> <p>There's currently no hook to allow you to return custom claims from the default userinfo action.</p> </blockquote> <p>@kevinchalet Can I some how add my own scope? Otherwise, is there any way I can return on authorization - my user profile? (Include company and some.more fields)?</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/stevetayloruk"><img src="https://avatars.githubusercontent.com/u/5065543?v=4" />stevetayloruk</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>I'm looking to do the same, but to use the existing defined claims i.e. <code>given_name</code>. But my custom <code>UserClaimsPrincipalFactory</code> doesn't seem to run. When does the <code>GenerateClaimsAsync()</code> get called / meant to run? My breakpoint never seems to be hit.</p> <p>Thanks</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/vitalybrandes"><img src="https://avatars.githubusercontent.com/u/61165619?v=4" />vitalybrandes</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <blockquote> <blockquote> <p>The userinfo endpoint only returns a limited predefined set, so your custom claims are simply ignored: <a href="https://github.com/OrchardCMS/OrchardCore/blob/dev/src/OrchardCore.Modules/OrchardCore.OpenId/Controllers/UserInfoController.cs">https://github.com/OrchardCMS/OrchardCore/blob/dev/src/OrchardCore.Modules/OrchardCore.OpenId/Controllers/UserInfoController.cs</a> There's currently no hook to allow you to return custom claims from the default userinfo action.</p> </blockquote> <p>@kevinchalet Can I some how add my own scope? Otherwise, is there any way I can return on authorization - my user profile? (Include company and some.more fields)?</p> </blockquote> <p>@kevinchalet Any recomandation on this?</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/kevinchalet"><img src="https://avatars.githubusercontent.com/u/6998306?v=4" />kevinchalet</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>You can certainly create custom scopes, but someone will need to implement the mapping logic so that the user controller returns custom claims.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/jtkech"><img src="https://avatars.githubusercontent.com/u/8586360?v=4" />jtkech</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>@stevetayloruk </p> <p>See what our <code>DefaultUserClaimsPrincipalFactory</code> does and how it is registered, then see in the <code>OC.Demo</code> module how it is replaced by the <code>DemoUserClaimsPrincipalFactory</code> in the <code>OC.Demo</code> module startup. Notice that the <code>OC.Demo</code> has a dependency on <code>OC.Users</code> in its <code>Manifest.cs</code> so that its startup <code>ConfigureServices()</code> runs after the <code>OC.Users</code> one.</p> </div> </div> <div class="comment"> <div class="user"> <a rel="noreferrer nofollow" target="_blank" href="https://github.com/stevetayloruk"><img src="https://avatars.githubusercontent.com/u/5065543?v=4" />stevetayloruk</a> commented <strong> 4 years ago</strong> </div> <div class="markdown-body"> <p>Thank you @jtkech! That's sorted it.</p> <p>All that was required was to add <code>Dependencies = new []{ "OrchardCore.Users" }</code> to the manifest. </p> <p>I didn't realise that the manifest dependencies had any more effect other than enabling depended features.</p> <p>Cheers</p> <p>Steve</p> </div> </div> <div class="page-bar-simple"> </div> <div class="footer"> <ul class="body"> <li>© <script> document.write(new Date().getFullYear()) </script> Githubissues.</li> <li>Githubissues is a development platform for aggregating issues.</li> </ul> </div> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script> <script src="/githubissues/assets/js.js"></script> <script src="/githubissues/assets/markdown.js"></script> <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/highlight.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.4.0/build/languages/go.min.js"></script> <script> hljs.highlightAll(); </script> </body> </html>