私は IdentityServer3 を初めて使用し、セットアップを開始したばかりです。順調に進んでいるようで、Kevin Dockx の Pluralsight コース ( http://www.pluralsight.com/courses/building-securing-restful-api -aspdotnet)--カスタム ユーザー サービスを使用しています。
MVC アプリから ID サーバーへの認証はうまく機能しますが、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 は常に Unauthorized であり、以下の「無効なトークン」ベアラー メッセージが表示されます。
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;
}
}