1

我是 IdentityServer3 的新手,刚刚开始设置它。它似乎进展顺利,我一直在为 MVC 应用程序开发混合流程,类似于 Kevin Dockx 的 Pluralsight 课程 ( http://www.pluralsight.com/courses/building-securing-restful-api -aspdotnet)--我正在使用自定义用户服务。

从 MVC 应用程序到我的身份服务器的身份验证效果很好,但是当我调用 userinfo 端点时,我总是得到一个 Unauthorized,响应中的 Bearer 是“无效令牌”。

我正在传递从原始 OpenIdConnectAuthentication 调用返回的访问令牌,它在 JWT 调试器中解码为以下内容:

{
  "client_id": "mvc",
  "scope": [
    "openid",
    "profile",
    "actioncenter"
  ],
 "sub": "erik",
 "amr": "password",
 "auth_time": 1437591012,
 "idp": "idsrv",
 "iss": "https://id.local/",
 "aud": "https://id.local/resources",
 "exp": 1437594614,
 "nbf": 1437591014
}

我还注意到响应内容带有“RunToCompletion”之类的内容。我已经从 Github 下载了源代码以查看调试的可能性,并怀疑它比我正在运行的 NuGet 包(1.6.2)更新。

我怀疑我做错了什么,但我还没有看到它。任何帮助,将不胜感激。

我已经包含了我认为相关的代码。

从 ID 服务器:

static class Clients
{
    public static List<Client> Get()
    {
        return new List<Client>
        {                
            new Client
            {
                ClientName = "MVC Client",
                ClientId = "mvc",
                Enabled = true,
                RequireConsent = true,

                RedirectUris = new List<string>     
                                   { "https://localhost:44300/" },
                AccessTokenType = AccessTokenType.Jwt,

                Flow = Flows.Hybrid,
                ScopeRestrictions = new List<string>()
                {
                    Constants.StandardScopes.OpenId,
                    Constants.StandardScopes.Profile,                       
                    "actioncenter"
                }

            }
        };
    }
static class Scopes
{
    public static List<Scope> Get()
    {
        return new List<Scope>
        {
            //identity scopes
            StandardScopes.OpenId,
            StandardScopes.Profile,
            //StandardScopes.EmailAlwaysInclude,
            //StandardScopes.PhoneAlwaysInclude,
            StandardScopes.Roles,

            //resource scopes
            new Scope
            {
                Name = "actioncenter",
                Type = ScopeType.Resource,
                Emphasize = false,
                Enabled = true,
                DisplayName = "Action Center"                    
            }
        };
    }
public class NwpIdentityUserService : IUserService
{
    public class CustomUser
    {
        public string Subject { get; set; }  // identifier for user
        public string Provider { get; set; } // provider name that did the auth for the user
        public string ProviderId { get; set; } // userid from the provider for this user
        public List<Claim> Claims { get; set; }
    }

    public Task<AuthenticateResult> PreAuthenticateAsync(SignInMessage message)
    {
        return Task.FromResult<AuthenticateResult>(null);
    }

    public Task<AuthenticateResult> AuthenticateLocalAsync(string username, string password, SignInMessage message)
    {
        AuthenticateResult result;

        if (username != password)
            result = new AuthenticateResult("Invalid username/password");
        else
            result = new AuthenticateResult(username, "erik", new List<Claim> { new Claim("role", "writer") });

        return Task.FromResult(result);
    }

    public Task<AuthenticateResult> AuthenticateExternalAsync(ExternalIdentity externalUser, SignInMessage message)
    {
        //var ourUserId = GetOurUserId()
        // LOGIC:
        // From the information in externalUser, determine our user ID
        // Assuming valid, return a new authenticate result with the nwp user name, claims, etc.

        return Task.FromResult<AuthenticateResult>(null);
    }

    public Task SignOutAsync(ClaimsPrincipal subject)
    {
        return Task.FromResult(0);
    }

    public Task<IEnumerable<Claim>> GetProfileDataAsync(ClaimsPrincipal subject, IEnumerable<string> requestedClaimTypes = null)
    {
        var nwpUserId = GetOurUserId(subject);
        if (nwpUserId == null)
            return Task.FromResult<IEnumerable<Claim>>(null);

        var claims = GetOurClaimsForUser(nwpUserId);
        return Task.FromResult(claims.Where(a => requestedClaimTypes.Contains(a.Type)));
    }

    private List<Claim> GetOurClaimsForUser(int? ourUserId)
    {
        var claims = new List<Claim>();
        claims.Add(new Claim("role", "basicuser"));

        return claims;
    }

    public Task<bool> IsActiveAsync(ClaimsPrincipal subject)
    {
        return Task.FromResult(GetOurUserId(subject) != null);
    }

    private int? GetOurUserId(ClaimsPrincipal subject)
    {
        var userclaim = subject.Claims.FirstOrDefault(a => a.Type == "name");
        if (userclaim == null)
            return null;

        return 123;
    }
}

以下是来自 MVC 客户端应用程序的相关代码 - response.StatusCode 始终未授权,并带有以下“无效令牌”承载消息:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Cookies"
        });

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            ClientId = "mvc",
            Authority = "https://id.local/identity/",
            RedirectUri = "https://localhost:44300/",
            SignInAsAuthenticationType = "Cookies",
            ResponseType = "code id_token token",
            Scope = "openid profile actioncenter",

            Notifications = new OpenIdConnectAuthenticationNotifications()
            {
                MessageReceived = async n =>
                {
                    var userInfo = await GetUserInfoFromEndpoint(n.ProtocolMessage.AccessToken);
                }

            }
        });
    }

    private async Task<JObject> GetUserInfoFromEndpoint(string accessToken)
    {
        var client = new HttpClient();
        client.SetBearerToken(accessToken);

        var response = await client.GetAsync("https://id.local/identity/connect/userinfo");

        if (response.StatusCode == HttpStatusCode.OK)
        {
            var json = await response.Content.ReadAsStringAsync();
            return JObject.Parse(json);
        }
        var result = response.Content.ReadAsStringAsync();
        return null;
    }

}
4

1 回答 1

0

根据 Ming 的建议查看 Thinktecture 日志后,我发现问题在于框架正在对 IsUserActiveAsync 进行调用,并且由于我的模拟代码中的一个小错误而返回 false。当我修复它时,一切都开始工作了。

于 2015-07-23T15:29:10.790 回答