IdentityServer4 + ASP.NET Core API + Angular:登录/身份验证

6
我正在使用IdentityServer4来处理ASP.NET Core API中的身份验证和授权。客户端使用Angular4。 我知道可以使用令牌端点(http://myapidomain/connect/token)通过使用grantype = ResourceOwnerPassword来获取access_token。这意味着我在登录UI中提供usernamepassword进行身份验证。
我的问题是:我们还需要实现API Account/Login吗?我认为IdentityServer4已经自动处理了通过cookie身份验证中间件的登录。 如果我们需要实现API Account/Login,那么最佳实践是什么? 我在某个地方读到的是使用这个来登录。
await  HttpContext.Authentication.SignInAsync(identityUser.Id,                                                                             identityUser.UserName);

这是注销的代码

await HttpContext.Authentication.SignOutAsync

我的第二个问题是: 当我从connect/token获取access_token时,我尝试通过访问http://myapidomain/connect/userinfo获取用户信息。但是我总是得到405错误代码。 我的哪些部分有问题?
在Angular客户端中。
authFormHeaders() {
    const header = new Headers();
    header.append('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
    header.append('Accept', 'application/json');
    header.append('Authorization', 'Bearer ' + this.oidcSecurityCommon.getAccessToken());
    return header;
  }

getUserInfo() {
        let self = this;
        let options = new RequestOptions({
            method: RequestMethod.Get,
            headers: this.authService.authFormHeaders()
        });
        return self.http.get(this.authWellKnownEndpoints.userinfoEndpoint, options)
            .map((res: Response) => {
                return res.json();
            })
            .catch(self.appService.handleError);
    }

在我的API服务器端:
CorsPolicyBuilder corsBuilder = new CorsPolicyBuilder()
                .AllowAnyHeader()
                .AllowAnyMethod()
                .AllowAnyOrigin()
                .AllowCredentials();
            services.AddCors(opts =>
            {
                opts.AddPolicy("AllowAllOrigins", corsBuilder.Build());
            });

var url = optionsAccessor.Value.SystemConfig.Authority;
            app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
            {
                Authority = url,
                RequireHttpsMetadata = false,
                ApiName = "netpower.qms.saas.api"/*,
                AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId }*/
            });
app.UseCors("AllowAllOrigins");
1个回答

3
对于使用 Angular 的客户端,应该使用 Implicit 而不是 ResourceOwnerPassword。在资源所有者与客户端建立信任关系(例如设备操作系统或高度特权的应用程序)的情况下,资源所有者密码凭据授权类型是合适的。授权服务器在启用此授权类型时应格外小心,仅在其他流程不可行的情况下才允许使用 (来自 OAuth 规范)。

资源所有者密码授权类型允许通过向令牌终结点发送用户名称和密码来代表用户请求令牌。这被称为“非交互式”身份验证,一般不推荐使用。在某些遗留或第一方集成方案中可能有原因需要使用此授权类型,但通常建议使用类似 implicit 或 hybrid 的交互式流程进行用户身份验证。

对于使用 Implicit 实现,您可以参考 这个,对于使用 ResourceOwnerpassword,请参考 这个
资源类型的流程如下:
+----------+
 | Resource |
 |  Owner   |
 |          |
 +----------+
      v
      |    Resource Owner
     (A) Password Credentials
      |
      v
 +---------+                                  +---------------+
 |         |>--(B)---- Resource Owner ------->|               |
 |         |         Password Credentials     | Authorization |
 | Client  |                                  |     Server    |
 |         |<--(C)---- Access Token ---------<|               |
 |         |    (w/ Optional Refresh Token)   |               |
 +---------+                                  +---------------+

对于使用Angular和Identity Server 4的ResourceOwnerPassword类型,您可以参考此GitHub存储库(链接),其中还包含客户端和服务器端的一些示例代码。
步骤如下:
  1. 资源所有者提供其用户名和密码给客户端。
  2. 客户端通过在请求中包括来自资源所有者的凭据,从授权服务器的令牌终结点请求访问令牌。在发送请求时,客户端会对授权服务器进行身份验证。
  3. 授权服务器对客户端进行身份验证并验证资源所有者凭据,如果有效,则发放访问令牌。
我们还需要实现API帐户/登录吗? 不,您不需要实现。正如您所怀疑的那样,这是在授权服务器中完成的。您将向Identity Server 4身份验证服务器发送用户名和密码,它将为您提供Bearer令牌。您的中间件(app.UseIdentityServerAuthentication)将对您的应用程序的请求进行身份验证。 我尝试通过访问http://myapidomain/connect/userinfo来获取用户信息。但我总是收到405错误代码。我缺少了什么? 您可以查看身份验证服务器日志以查找缺少了什么。我捕获了一个示例请求,它看起来像这样。
POST http://myapidomain/connect/token HTTP/1.1
Host: myapidomain
Proxy-Connection: keep-alive
Content-Length: 142
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
Origin: http://angularspawebapi.azurewebsites.net
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36
Content-Type: application/x-www-form-urlencoded


client_id=AngularSPA&grant_type=password&username=admin%40gmail.com&password=Admin01*&scope=WebAPI%20offline_access%20openid%20profile%20roles


GET http://myapidomain/connect/userinfo HTTP/1.1
Host: myapidomain
Proxy-Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjhDRTQ1ODAwQTAwNkExNkZGMzEwOTExMDVCRjNDNTY2MzgzNEUxQkEiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJqT1JZQUtBR29XX3pFSkVRV19QRlpqZzA0Ym8ifQ.eyJuYmYiOjE1MDAwOTk4NjIsImV4cCI6MTUwMDEwMDc2MiwiaXNzIjoiaHR0cDovL2FuZ3VsYXJzcGF3ZWJhcGkuYXp1cmV3ZWJzaXRlcy5uZXQiLCJhdWQiOlsiaHR0cDovL2FuZ3VsYXJzcGF3ZWJhcGkuYXp1cmV3ZWJzaXRlcy5uZXQvcmVzb3VyY2VzIiwiV2ViQVBJIl0sImNsaWVudF9pZCI6IkFuZ3VsYXJTUEEiLCJzdWIiOiI5Y2I1ZGViNS1iZWRmLTRkMWItOThkNS05ZTFjYTgwNzVhYjAiLCJhdXRoX3RpbWUiOjE1MDAwOTk4NjEsImlkcCI6ImxvY2FsIiwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJzY29wZSI6WyJvcGVuaWQiLCJwcm9maWxlIiwicm9sZXMiLCJXZWJBUEkiLCJvZmZsaW5lX2FjY2VzcyJdLCJhbXIiOlsicHdkIl19.CZAGtK5hvwgkMvX9NQ-8zTFr8Cv3SRVhM-u1WdqdLwI-qbdknfhhVFFHFpPzEWEJnKhsi3aE_BOb_UtRiDBWNHzlXAGmKSjtd70HOlT3dR9Sj_v09Ld15On3HihgfeDwOzIt10ZYwwjRr1tRCf6Ro41FQ2UrzBYcSFe47md7DSlxPXbjnQAHdu8gHMITFF8Nqx0V9OEw21fofRdBalOpvxf1IBhsJwWLyL4bLFYya8jNispK4MnN_tdaS8kxIMZ8iC_IUlhY4XEj5pkDBA9r8ad_Vn5WavO3Lmr4Tew4uBhlFhbE-Qr6EpErAEBVHVtJYs70XXGJJ7QQLoFNmO5M9w
content-type: text/plain

谢谢您的回复。那么我们需要实现登录API吗? - jack.pop
2
我认为你过于强调“不要使用ResourceOwnerPassword流程”的问题。正如你引用的文本所说,这是适合第一方集成的流程,特别是当你拥有客户端、API、身份服务器和它们是你的用户时,它提供了更清晰的UX。当然,你不希望第三方客户端为你的用户使用该流程,但我不同意客户端与之建立的信任关系需要是“高度特权”或操作系统级别的观点。 - Mashton
@Mashton,我并不是凭空捏造的。这在OAuth 规范中有明确说明。 - Rohith
感谢@RohithRajan的回复。这是非常有用的信息。如果IdentityServer处理身份验证,那么我们如何设置cookie/token的过期时间?我们是在服务器端还是客户端控制过期的token呢? - jack.pop
为了验证一切正常,请尝试从这里获取以下代码 // 请求令牌 var tokenClient = new TokenClient(disco.TokenEndpoint, "ro.client", "secret"); var tokenResponse = await tokenClient.RequestResourceOwnerPasswordAsync("alice", "password", "api1");if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; }Console.WriteLine(tokenResponse.Json); Console.WriteLine("\n\n"); - Rohith
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接