简体   繁体   English

Angular 客户端,WebAPI 服务器 - userManager.GetUserAsync() 方法时的 cookie 问题

[英]Angular client, WebAPI server - cookie issue when userManager.GetUserAsync() method

I'm preparing WebAPI where the client (Angular) is asking via HTTP for logging in and current user.It works fine, when I'm sending POST and GET requests from Swagger (works on https://localhost:44322/swagger/index.html).我正在准备 WebAPI,其中客户端(Angular)通过 HTTP 询问登录和当前用户。当我从 Swagger 发送 POST 和 GET 请求时(适用于 Z5E056C500A1C2206A75ADEZ/0B540D38B540D3),它工作正常index.html)。 I receive all necessary answers, but fun thing happens when I'm trying to do so from Angular (works on https://localhost:4200).我收到了所有必要的答案,但是当我尝试从 Angular (适用于 https://localhost:4200)这样做时,会发生有趣的事情。 CORS origin turned on, headers allowed, any method allowed, credentials allowed... I think I run into a cookie-related issue, because, when I open both cards (swagger and angula) in the same browser window, I'm able to do everything find, but when I separate them, swagger works, but Angular stop seeing cookies which come from the server-side. CORS 源已打开,允许标头,允许任何方法,允许凭据...我想我遇到了与 cookie 相关的问题,因为当我在同一个浏览器 window 中打开两张卡(swagger 和 angula)时,我可以做所有事情,但是当我将它们分开时, swagger 可以工作,但是 Angular 停止看到来自服务器端的 cookies 。

I think I tried everything.我想我什么都试过了。 I tried to play withCredentials paremeter in HTTP requests, I tried to parametrize CORS to allow switch on AllowCredentials();我尝试在 HTTP 请求中使用凭据参数,我尝试参数化 CORS 以允许打开 AllowCredentials(); method.方法。 Nothing worked.没有任何效果。

So, Swagger can send requests like below.因此,Swagger 可以发送如下请求。

在此处输入图像描述

I also implemented HTTP requests from Angular.我还实现了来自 Angular 的 HTTP 请求。 Below login.component.ts在 login.component.ts 下面

import { HttpClient } from '@angular/common/http';
import { Message } from '@angular/compiler/src/i18n/i18n_ast';
import { Component, OnInit } from '@angular/core';
import { first } from 'rxjs';
import { UserService } from '../user.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  response: any;
  currentUser = {
    firstName: "",
    lastName: ""
  };
  user: any;
  userLogin = {
    email: "",
    password: ""
  }

  firstName: string = "";
  lastName: string = "";

  constructor(private http: HttpClient, private service: UserService) { }

  ngOnInit(): void {
    this.getCurrentUser();
  }

  loginAction(): any {
    this.response = this.service.loginUser(this.userLogin);
    if(this.response){
      this.service.currentUser().subscribe((response: any) =>{
        this.currentUser.firstName = (response as any).firstName;
      });
    }
  }
  logoutAction():any{
    this.service.logoutUser();
  }

  getCurrentUser(){
    this.service.currentUser().subscribe((response: any) =>{
      this.currentUser.firstName = (response as any).firstName;
    });    
  }

}

And user.service.ts和 user.service.ts

export class UserService {

  readonly taskAPIUrl = "https://localhost:44322/api";
  
  constructor(private http: HttpClient) { }

  loginUser(userLogin :any) {
    return this.http.post("https://localhost:44322/api/UserLogin",userLogin).subscribe();
  }

  logoutUser(): any {
    return this.http.post<any>("https://localhost:44322/api/UserLogin/logout", {withCredentials: true}).subscribe();
  }

  currentUser(): any {
    return this.http.get<any>("https://localhost:44322/api/UserLogin/getCurrentUser", {withCredentials: true});
  }

Here is Startup.cs这是 Startup.cs

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ToDoListAPI.Data;
using ToDoListAPI.Models;

namespace ToDoListAPI
{
    public class Startup
    {
        private string myAllowSpecificOrigins = "_myAllowSpecificOrigins";
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "ToDoListAPI", Version = "v1" });
            });

            services.AddDbContext<DataContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("ConnectionString"));
            });

            

            //Enable CORS
            services.AddCors(options =>
            {
                options.AddPolicy(name: myAllowSpecificOrigins,
                    builder =>
                    {
                        builder.WithOrigins("https://localhost:4200").
                        AllowAnyMethod().
                        AllowAnyHeader().
                        AllowCredentials();
                    });
            });

            services.AddIdentity<ApplicationUser, IdentityRole>(options =>
            {
                options.ClaimsIdentity.UserNameClaimType = "UserID";
            }).
                     AddEntityFrameworkStores<DataContext>().
                     AddDefaultTokenProviders();

            services.ConfigureApplicationCookie(options =>
            {
                options.Cookie.HttpOnly = false;
            });


        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ToDoListAPI v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseCors(myAllowSpecificOrigins);

            app.UseAuthentication();

            app.UseAuthorization();            

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

UserLoginController.cs where I send HTTP requests我发送 HTTP 请求的 UserLoginController.cs

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;
using ToDoListAPI.Models;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace ToDoListAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserLoginController : ControllerBase
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signInManager;

        public UserLoginController(UserManager<ApplicationUser> userManager,
                                    SignInManager<ApplicationUser> signInManager)
        {
            _userManager = userManager;
            _signInManager = signInManager;
        }
        // GET: api/<UserLoginController>
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/<UserLoginController>/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        [HttpGet]
        [Route("getCurrentUser")]
        public async Task<IActionResult> GetCurrentUser()
        {
            var user = await _userManager.GetUserAsync(User);

            if (user == null)
            {
                return Unauthorized();
            }
            return Ok(user);
        }

        // POST api/<UserLoginController>
        [HttpPost]
        public async Task<IActionResult> Login([FromBody] UserLogin userLoginDto)
        {
            var foundUser = await _userManager.FindByEmailAsync(userLoginDto.Email);
            if (foundUser == null)
            {
                return NotFound();
            }
            var result = await _signInManager.PasswordSignInAsync(
                foundUser, userLoginDto.Password, true, false);
            if (result.Succeeded)
            {
                return Ok();
            }
            return NotFound();
        }


        // POST api/<UserLoginController>
        // in progress
        [HttpPost]
        [Route("logout")]
        public async void Logout()
        {
            await _signInManager.SignOutAsync();
        }


        // DELETE api/<UserLoginController>/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

Please help, I think I stuck somewhere...请帮忙,我想我卡在某个地方......

Here is example of UserLogin request from Swagger这是来自 Swagger 的 UserLogin 请求示例在此处输入图像描述

And here from angular client这里来自 angular 客户端在此处输入图像描述

As you can see, Swagger has a lot more in the request and response stay the same.如您所见,Swagger 在请求和响应中保持不变。 The biggest problem is when I send getCurrentUser() request.最大的问题是当我发送 getCurrentUser() 请求时。

Swagger: Swagger: 在此处输入图像描述

and angular和 angular

在此处输入图像描述

Ok.好的。 For angular it should look something like this.对于 angular 它应该看起来像这样。 In user.service.ts methods should return Observalbe.在 user.service.ts 方法应该返回 Observalbe。

For an example:例如:

loginUser(userLogin : "here should be model class): Observable<Any> {
    return this.http.post("https://localhost:44322/api/UserLogin",userLogin).subscribe(repond => {return respond});

       return this.httpClient
      .post("https://localhost:44322/api/UserLogin",userLogin)
      .pipe(map(resposne =>{
          return resposne;
      }),
      catchError(error => {
        console.log(error);
      }));
  }

In login.component.ts login should look something like this:在 login.component.ts 中,登录应该如下所示:

loginAction() {
    this.service.loginUser(this.userLogin)
    .pipe(first())
    .subscribe( response =>{
        this.currentUser.firstName = response.firstName;
     }, error => {
        console.log(error); 
    });
  }

For GetCurrentUser in Controller file try tu parse tu yours id type instead of User this User.Identity.Name or User.Identity.Id对于 Controller 文件中的 GetCurrentUser 尝试你解析你的 id 类型而不是用户这个 User.Identity.Name 或 User.Identity.Id

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么UserManager.GetUserAsync在使用JWT时返回null? - Why does UserManager.GetUserAsync return null when using JWT? 为什么 UserManager.GetUserAsync 不返回? - why does UserManager.GetUserAsync not return? _userManager.GetUserAsync(User) 返回 null - _userManager.GetUserAsync(User) returns null JWT 身份验证 - UserManager.GetUserAsync 返回 null - JWT Authentication - UserManager.GetUserAsync returns null 为什么我们每个动作方法都必须调用await _userManager.GetUserAsync(User)? - Why do we have to invoke await _userManager.GetUserAsync(User) per action method? 当照片不存在时,UserManager.GetUserAsync(User).Result.ProfilePicture 失败 - UserManager.GetUserAsync(User).Result.ProfilePicture Failing when Photo does not exists UserManager.GetUserAsync(User)是否可以在具有Authorize属性的类中返回null? - Can UserManager.GetUserAsync(User) return null in a class with Authorize attribute? WEBAPI客户端服务器绑定信息 - WEBAPI client server binding information 使用 Angular 的服务器上的 WebApi 身份验证失败 - WebApi authentication failed on server with Angular c#webApi从Angular 2客户端发布时到达空数据 - c# webApi reaching null data when posting from Angular 2 client
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM