[英]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() 请求时。
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.