我是 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;
}
}