[英]How to us openid connect hybrid flow to call an Api on behalf of user (IdentityServer4 Asp.Net Core 2.0)?
I am attempting to use IdentityServer4 to have a web application call an API on behalf of the user. 我正在尝试使用IdentityServer4来让Web应用程序代表用户调用API。 I expect that the API will have the User Identity information for the user even though it is the web application making the request.
我希望该API将具有用户的用户身份信息,即使它是发出请求的Web应用程序也是如此。
Everything is working correctly (Authentication/Claims etc) except within the API User.Identity.Name
is null. 除了API
User.Identity.Name
为null外,其他所有东西都正常运行(身份验证/声明等)。 User.Identity.Name in the Web application is returning the correct username. Web应用程序中的User.Identity.Name返回正确的用户名。 bellow is an example of what I have tried.
波纹管是我尝试过的一个例子。
I am using IdentityServer4 v- 2.1.2 IdentityModel v- 3.1.1 Microsoft.AspNetCore.All v- 2.0.5 我正在使用IdentityServer4 v- 2.1.2 IdentityModel v- 3.1.1 Microsoft.AspNetCore.All v- 2.0.5
Just as some backround: I am folowing a PluralSight Tutorial - https://app.pluralsight.com/library/courses/aspnet-core-identity-management-playbook/table-of-contents 正如一些底色:我是一个如下因素教程PluralSight - https://app.pluralsight.com/library/courses/aspnet-core-identity-management-playbook/table-of-contents
API Controller API控制器
[Produces("application/json")]
[Route("api")]
public class ApiController : Controller
{
[Route("user")]
[Authorize]
public IActionResult GetUser()
{
return Content("User " + User.Identity.Name);
}
}
API Startup.cs - ConfigureServices method API Startup.cs-ConfigureServices方法
services.AddAuthentication()
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:44335";
options.Audience = "DemoApi";
options.TokenValidationParameters.NameClaimType = "name";
});
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
IdentityServer InMemory Client setup IdentityServer InMemory客户端设置
new Client()
{
ClientId = "WebApp",
AllowedGrantTypes = GrantTypes.Hybrid,
ClientSecrets = new [] {new Secret("MySecret".Sha256())},
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"DemoApi"
},
RedirectUris = { "https://localhost:44343/signin-oidc" },
PostLogoutRedirectUris = new List<string>
{
"https://localhost:44343/signout-callback-oidc"
},
AllowOfflineAccess = true,
RequireConsent = false
}
IdentityServer TestUser setup: IdentityServer TestUser设置:
new TestUser()
{
SubjectId = "1",
Username = "testname",
Password = "pass123",
Claims = new []
{
new Claim("name", "testname")
}
}
Web Application startup.cs ConfigureServices Method - Authentication setup Web应用程序startup.cs ConfigureServices方法-身份验证设置
services.AddAuthentication(options => {
options.DefaultChallengeScheme = "oidc";
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = "oidc";
}).AddOpenIdConnect("oidc", options => {
options.Authority = "https://localhost:44335/";
options.ClientId = "WebApp";
options.ClientSecret = "MySecret";
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.Scope.Add("DemoApi");
options.Scope.Add("offline_access");
options.SignedOutRedirectUri = "/";
options.TokenValidationParameters.NameClaimType = "name";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
}).AddCookie();
Web Application API call - Web应用程序API调用-
[Route("callapi")]
[Authorize]
public async Task<IActionResult> CallApi()
{
string accessToken;
try
{
accessToken = await GetAccessToken();
}
catch (System.Exception ex)
{
ViewBag.Error = ex.GetBaseException().Message;
return View();
}
var client = new HttpClient();
client.SetBearerToken(accessToken);
try
{
var content = await client.GetStringAsync("https://localhost:44379/api/user");
ViewBag.ApiResponse = content;
}
catch (Exception ex)
{
ViewBag.ApiResponse = ex.GetBaseException().Message;
}
ViewBag.AccessToken = accessToken;
ViewBag.RefreshToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);
return View();
}
private async Task<string> GetAccessToken()
{
var exp = await HttpContext.GetTokenAsync("expires_at");
var expires = DateTime.Parse(exp);
if (expires > DateTime.Now)
{
return await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);
}
return await GetRefreshedAccessToken();
}
private async Task<string> GetRefreshedAccessToken()
{
var disco = await DiscoveryClient.GetAsync("https://localhost:44335/");
var tokenClient = new TokenClient(disco.TokenEndpoint, "WebApp", "MySecret");
var refreshToken = await HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);
var tokenResponse = await tokenClient.RequestRefreshTokenAsync(refreshToken);
if (tokenResponse.IsError)
{
var auth = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
auth.Properties.UpdateTokenValue(OpenIdConnectParameterNames.AccessToken, tokenResponse.AccessToken);
auth.Properties.UpdateTokenValue(OpenIdConnectParameterNames.RefreshToken, tokenResponse.RefreshToken);
var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResponse.ExpiresIn);
auth.Properties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, auth.Principal, auth.Properties);
return tokenResponse.AccessToken;
}
throw tokenResponse.Exception;
}
Try setting up your API according to the official documentation . 尝试根据官方文档设置API。
From what I see, the differences are in the authentication type. 从我看来,区别在于身份验证类型。 You have
你有
services.AddAuthentication()
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:44335";
options.Audience = "DemoApi";
options.TokenValidationParameters.NameClaimType = "name";
});
while the docs say: 而文档说:
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://localhost:5000";
options.RequireHttpsMetadata = false;
options.ApiName = "api1";
});
Of course modify it with your authority url. 当然可以使用您的授权URL对其进行修改。 The other things seem legit.
其他事情似乎合法。
PS: The AddIdentityServerAuthentication
is coming with IdentityServer4.AccessTokenValidation
package PS:
AddIdentityServerAuthentication
与IdentityServer4.AccessTokenValidation
包一起提供
EDIT 编辑
Based on comments - remove this lines: 根据评论-删除以下行:
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
And lets see what happens. 让我们看看会发生什么。
EDIT 2 编辑2
After some discussions, we figured out that Zzz was using some Pluralsight tutorial for asp.net identity. 经过一些讨论,我们发现Zzz在使用一些Pluralsight教程来确定asp.net身份。 For those who are reading this, and they are starting implementing IdentityServer as an authentication for their applications - follow the official documentation and also check the samples .
对于那些正在阅读本文的人,他们开始实现IdentityServer作为其应用程序的身份验证-请遵循官方文档并检查示例 。
PS: And always enable logging. PS:始终启用日志记录。 It is everything and saves tons of hours.
这就是一切,可以节省大量时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.