【问题标题】:Thinktecture Identity Server v3 How to keep Claims from external providers?Thinktecture Identity Server v3 如何保持来自外部提供商的声明?
【发布时间】:2015-03-24 21:03:39
【问题描述】:

我正在尝试遵循简单的指南mvcGettingStarted。 现在,我已经实现了GoogleAuthentication 和FacebookAuthentication 提供程序,并且一切都按预期工作,我实际上可以登录,如果我使用我的身份服务器登录,我还可以获得每个用户的角色声明。 我想知道,如果我想保留外部提供商提供的所有索赔怎么办? 简单的例子。 这就是我的 Facebook 提供商设置的样子:

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

在 for each 循环中,我尝试将所有 Facebook 声明存储在 Identity 中,但是当我返回 SecurityTokenValidated 回调时,我的 Identity 没有它们。

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's 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);
                    ........

是因为我在操纵两个不同的身份吗? 有没有正确的方法来实现我想要做的事情? 谢谢你。

【问题讨论】:

    标签: c# claims-based-identity thinktecture-ident-server


    【解决方案1】:

    您可以在自定义用户服务实现中执行此操作。默认设置使来自外部提供者的声明可用。关于自定义用户服务的文档:https://identityserver.github.io/Documentation/docsv2/advanced/userService.html

    【解决方案2】:

    正如@brock-allen 所说,用户服务是正确的道路。 所以我继续实现了一个简单的 UserService

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

    像这样在我的工厂注册我的用户服务

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

    (当然这是我的 Startup 类中的 Configuration 方法)

    所以现在我可以在外部提供者(在本例中为 facebook)的身份验证回调中对外部用户进行身份验证,并指定我需要的所有声明:

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

    现在可以了

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

    并看到我的用户拥有 facebook 在身份验证期间提供的所有声明。 当然这段代码只是测试用的,还可以改进很多。

    【讨论】:

    • 我在理解本地和外部声明方面也遇到了一些困难。见stackoverflow.com/questions/28748000/…。你能对此有所了解吗?
    • @Daniele 你能发布整个代码吗?我很感兴趣。谢谢
    • AuthenticateExternalAsync 是扩展方法吗?我找不到接受这些参数的人。我在这里得到的只接受一个 ExternalAuthenticationContext 作为参数并且没有重载。
    • 这里一样@BrunoGrisoliaCasarotti 你知道它是从哪里来的吗?
    猜你喜欢
    • 2015-04-08
    • 2019-06-07
    • 2015-05-29
    • 2014-04-01
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 2013-12-13
    • 2015-02-12
    相关资源
    最近更新 更多