简体   繁体   English

如何使用openid连接混合流来代表用户(IdentityServer4 Asp.Net Core 2.0)调用Api?

[英]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;
}

API - User.Identity API-用户身份 在此处输入图片说明

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: AddIdentityServerAuthenticationIdentityServer4.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.

相关问题 如何在ASP.NET WEB API中验证由identityserver4生成的OpenID Connect访问令牌 - How to Validate OpenID Connect Access Token generated by identityserver4 in ASP.NET WEB API 如何在ASP.NET Core 2.0 Web API中添加IdentityServer4和Auth0的Jwt身份验证? - How do I add Jwt authentication from IdentityServer4 and Auth0 in an ASP.NET Core 2.0 web api? 将IdentityServer4集成到ASP.NET Core MVC和API - Integrating IdentityServer4 to ASP.NET Core MVC and API IdentityServer4和ASP.NET MVC(.NET 4.6.2)之间的OpenID连接 - OpenID connect between IdentityServer4 and ASP.NET MVC (.NET 4.6.2) asp.net core 3 和 identityserver4 - asp.net core 3 and identityserver4 IdentityServer4 Asp.Net 核心身份 - IdentityServer4 Asp.Net Core Identity 如何在 controller 中使用 IdentityServer4 获取 ASP.NET 核心中的当前用户? - How to get current user in ASP.NET core with IdentityServer4 in a controller? IdentityServer4,带有AuthenticationOptions类的asp.net core2.0错误 - IdentityServer4 with asp.net core2.0 erron on AuthenticationOptions class Identityserver4 / OpenId Connect,混合模式,令牌刷新失败 - Identityserver4/OpenId Connect, Hybrid mode, Token Refresh Fails 将 OpenID Connect 用户映射到 ASP.NET Core 身份用户 - Map OpenID Connect User to ASP.NET Core Identity User
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM