Thinktecture Identity Server v3如何保持外部提供商的声明?

时间:2015-01-26 12:40:45

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

我正在尝试遵循简单指南mvcGettingStarted。 现在,我已经实现了GoogleAuthenticationFacebookAuthentication个提供程序,一切都按预期工作,我实际上可以登录,如果我使用我的身份服务器登录,我还获得了角色声明用户。 我想知道,如果我想保留外部提供商提供的所有索赔怎么办? 简单的例子。 这就是我的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);

在每个循环中我试图将所有Facebook声明存储在身份中,但当我回到SecurityTokenValidated回调时,我的身份没有它们。

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

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

2 个答案:

答案 0 :(得分:6)

正如@ 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提供的所有声明。 当然这段代码仅用于测试目的,可以进行很多改进。

答案 1 :(得分:4)

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