使用.Net Core 2.1和Identity Server 4
我有3个初创公司,分别是IS4,MVC App和API App。我可以正常登录MVC应用程序,并检索我的access_token。我尝试使用此令牌访问API,但无法授权该请求。
这是我的IS4 Startup.cs本地主机:5000
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<IdentityContext>()
.AddDefaultTokenProviders();
services.AddMvc();
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
services.AddIdentityServer()
.AddAspNetIdentity<ApplicationUser>()
.AddConfigurationStore(configDb =>
{
configDb.ConfigureDbContext = db => db.UseNpgsql(Configuration.GetConnectionString("IdentityServer4ConfigurationContext"),
sql => sql.MigrationsAssembly(typeof(IdentityServer4Startup).GetTypeInfo().Assembly.GetName().Name));
})
.AddOperationalStore(operationDb =>
{
operationDb.ConfigureDbContext = db => db.UseNpgsql(Configuration.GetConnectionString("IdentityServer4PersistedGrantContext"),
sql => sql.MigrationsAssembly(typeof(IdentityServer4Startup).GetTypeInfo().Assembly.GetName().Name));
})
.AddDeveloperSigningCredential();
我的MVC Startup.cs本地主机:61000
services.AddMvc();
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<IdentityContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies";
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ClientId = "mvc";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("api1");
options.Scope.Add("offline_access");
options.Scope.Add("openid");
options.Scope.Add("email");
});
还有我的API Startup.cs localhost:62000
services.AddMvc();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddIdentityServerAuthentication("oidc", options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ApiName = "api1";
});
我的客户信息是
new Client {
ClientId = "mvc",
ClientName = "Example Mvc",
AllowedGrantTypes = GrantTypes.Hybrid,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"role",
"api1"
},
RedirectUris = new List<string> {"http://localhost:61000/signin-oidc"},
PostLogoutRedirectUris = new List<string> { "http://localhost:61000/signout-callback-oidc" }
}
和API资源
new ApiResource {
Name = "api1",
DisplayName = "Custom API",
Description = "Custom API Access",
UserClaims = new List<string> {"role"},
ApiSecrets = new List<Secret> {new Secret("scopeSecret".Sha256())},
Scopes = new List<Scope> {
new Scope("api1"),
}
}
每当我以客户端身份登录时尝试调用API时,我都无法访问它。它将给出错误
[10:40:11 ERR] Invalid redirect_uri: http://localhost:62000/signin-oidc
{
"ClientId": "mvc",
"ClientName": "MVC Client",
"AllowedRedirectUris": [
"http://localhost:61000/signin-oidc"
],
"SubjectId": "anonymous",
"RequestedScopes": "",
"Raw": {
"client_id": "mvc",
"redirect_uri": "http://localhost:62000/signin-oidc",
"response_type": "code id_token",
"scope": "openid profile api1 offline_access email",
"response_mode": "form_post",
"nonce": "636778932114224044.N2M1YzZhMjktMThjMS00ZGEyLWI1OGQtZjM1YmZiMzViNDVkNDQ2NDhjZWMtNzk4Mi00NTc2LWI2YzctNjAwMzkwNjI5NGE5",
"state": "CfDJ8EzT-5PsjT5Htj2FYGOkFvxTH4w-8q3uXGtc1wXYyvWMHyarfbV0cQz8cFh4ESIW33n4pwtIEmLhrTpX-0Y0-_HS24cWs05nR3npx1ZIAJsYr9hIqB9hj9Ic_QYkU2Z_bcjjnaynqfbF5KIyyQhYGNlDxDfknwZUTXpPzTFEhLTcnam7O-b-xV9a3e9iWARoFZRBLjGV5Hs5i-8jS5EGM9DpqwcvrUjSUlRVDP-TzBBhYPhswn2hKsjkhL26_Gp9lluoKNLOvUVM-yq1zHbbI9uTcZzS_2GtbQoPuuGTmCuOoV-c-K2IztzXP88W-osYaY9wQP2qi8aXD951hrAhYbo",
"x-client-SKU": "ID_NETSTANDARD1_4",
"x-client-ver": "5.2.0.0"
}
}
我不认为我需要注册redirect_uri。但是无论如何我都尝试过,当我执行相同的请求时,它只会返回登录屏幕。因为它无法验证我的请求。
这是我从MVC发送到API的HttpClient请求
var apiUrl = "http://localhost:62000/test/api";
var authenticate = await HttpContext.AuthenticateAsync("Cookies");
var accessToken = authenticate.Ticket.Properties.GetTokenValue("access_token");
var client = new HttpClient();
client.SetBearerToken(accessToken);
var response = await client.GetAsync(apiUrl);
return Json(response.Content.ReadAsStringAsync());
从所有示例和文档中,我看不到为什么它不起作用。任何帮助将不胜感激。
当我尝试使用不记名令牌调用API时,这是IS4的输出。
[12:38:58 INF] Request starting HTTP/1.1 GET http://localhost:5000/connect/authorize?client_id=mvc&redirect_uri=http%3A%2F%2Flocalhost%3A62000%2Fsignin-oidc&response_type=code%20id_token&scope=openid%20profile%20api1%20offline_access%20email&response_mode=form_post&nonce=636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0&state=CfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg&x-client-SKU=ID_NETSTANDARD1_4&x-client-ver=5.2.0.0
[12:38:58 INF] Invoking IdentityServer endpoint: IdentityServer4.Endpoints.AuthorizeEndpoint for /connect/authorize
[12:38:58 INF] ValidatedAuthorizeRequest
{
"ClientId": "mvc",
"ClientName": "MVC Client",
"RedirectUri": "http://localhost:62000/signin-oidc",
"AllowedRedirectUris": [
"http://localhost:62000/signin-oidc",
"http://localhost:61000/signin-oidc"
],
"SubjectId": "anonymous",
"ResponseType": "code id_token",
"ResponseMode": "form_post",
"GrantType": "hybrid",
"RequestedScopes": "openid profile api1 offline_access email",
"State": "CfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg",
"Nonce": "636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0",
"Raw": {
"client_id": "mvc",
"redirect_uri": "http://localhost:62000/signin-oidc",
"response_type": "code id_token",
"scope": "openid profile api1 offline_access email",
"response_mode": "form_post",
"nonce": "636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0",
"state": "CfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg",
"x-client-SKU": "ID_NETSTANDARD1_4",
"x-client-ver": "5.2.0.0"
}
}
[12:38:58 INF] Showing login: User is not authenticated
[12:38:58 INF] Request finished in 138.5606ms 302
[12:38:58 INF] Request starting HTTP/1.1 GET http://localhost:5000/account/login?returnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id%3Dmvc%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A62000%252Fsignin-oidc%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520api1%2520offline_access%2520email%26response_mode%3Dform_post%26nonce%3D636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0%26state%3DCfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg%26x-client-SKU%3DID_NETSTANDARD1_4%26x-client-ver%3D5.2.0.0
[12:38:58 INF] Route matched with {action = "Login", controller = "Account"}. Executing action ASC.ADEX.Runtime.Controllers.AccountController.Login (ASC.ADEX.Runtime)
[12:38:58 INF] Executing action method ASC.ADEX.Runtime.Controllers.AccountController.Login (ASC.ADEX.Runtime) with arguments (["/connect/authorize/callback?client_id=mvc&redirect_uri=http%3A%2F%2Flocalhost%3A62000%2Fsignin-oidc&response_type=code%20id_token&scope=openid%20profile%20api1%20offline_access%20email&response_mode=form_post&nonce=636779003387253889.MThjYjQ5MzItOTY3NS00NmM1LWJhZDItMzkxMzYyMWQzZTUwZThjNThmMjUtMmQyZC00M2YyLTk3OTktN2E3OTc1ZDcyNmM0&state=CfDJ8EzT-5PsjT5Htj2FYGOkFvzm1YFOhTLHlbLS3LpJd_xUBgDz8hWjGkXxSzfnWKqoVU5d4L7ESHCSDGxqmxqnMh1-j-IUGBLzt5uEYFi2M4QV6WmGN1Lv5bMkUDRbrE9pdCNc7vLDUDZY1OWlp4HfQ0vEMr8-OfUH4Q00fOn1v9zpcE6QlHI5Aye9xiFOshHRyMCNwEEcVrLz4Y06Hsa-40OKom3xb8sie09JtiSMZJL9WyKgKYGRgqUIpD6wqryBafzMl_t1tvegYWESq59TafnIpvrFd3ifdOzJx6cXul4ZCcFv0wfvsqpUgCF7t7xyMSwtheDSiE2AySkbnrpr_Dg&x-client-SKU=ID_NETSTANDARD1_4&x-client-ver=5.2.0.0"]) - Validation state: Valid
[12:38:58 INF] Executed action method ASC.ADEX.Runtime.Controllers.AccountController.Login (ASC.ADEX.Runtime), returned result Microsoft.AspNetCore.Mvc.ViewResult in 41.3848ms.
[12:38:58 INF] Executing ViewResult, running view Login.
[12:38:58 INF] Executed ViewResult - view Login executed in 1.8018ms.
[12:38:58 INF] Executed action ASC.ADEX.Runtime.Controllers.AccountController.Login (ASC.ADEX.Runtime) in 78.939ms
[12:38:58 INF] Request finished in 83.6512ms 200 text/html; charset=utf-8
答案 0 :(得分:1)
我使用AddJwtBearer
设置了API身份验证,如下所示。我看到您使用AddIdentityServerAuthentication
。可能就是这个原因吗?
services.AddJwtBearer(o =>
{
o.Authority = "<id-server>";
o.Audience = "<api-audience>";
o.RequireHttpsMetadata = true;
});
并且API控制器指定了AuthenticationSchemes
,如下所示:
[Route("api/rates")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class RatesController : Controller
{
}
答案 1 :(得分:1)
通常,仅当 Client (即您的MVC应用)重定向到Identity Server时,您才能获得Invalid redirect_uri
,以便用户可以进行身份验证,而不是在调用API时或由API本身,因此您应该从API的配置中删除挑战并将其留给UI。您的API还需要用于对Identity Server进行某些反向通道调用的秘密,因此请将您API的Startup.cs更改为:
services.AddAuthorization();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(
options =>
{
options.Authority = "http://localhost:5000";
options.ApiName = "api1";
options.ApiSecret = "scopeSecret";
options.RequireHttpsMetadata = false;
// You will almost certainly want these at some point too,
// to prevent the API talking to the IS for every
// API call. Adjust the duration as desired.
options.EnableCaching = true;
options.CacheDuration = TimeSpan.FromMinutes(10);
});
您没有在API的Startup.cs中显示Configure()
部分,但请确保它具有
.UseAuthentication();
在呼叫之前
.AddMvc()
现在,您只需要用[Authorize]
装饰受保护的API方法,并确保您通过用户的承载令牌传递对这些API方法的调用。