即使使用 ASP.NET CORE 登录,我在 Angular 中也有 401 Unauthorized
Posted
技术标签:
【中文标题】即使使用 ASP.NET CORE 登录,我在 Angular 中也有 401 Unauthorized【英文标题】:I have a 401 Unauthorized in Angular even when login whit ASP.NET CORE 【发布时间】:2021-09-25 16:08:04 【问题描述】:我已经在 Angular 中创建了一个登录名。登录后我可以登录,我得到一个 jwt 密钥。我的问题是当我登录时,我应该能够从我的 api 获取客户列表。我在这里遵循https://code-maze.com/authentication-aspnetcore-jwt-2/ 的指示,我不明白为什么当我尝试从我的 api 获取客户端时会得到 401。
这里是相关的角度文件
我有 auth-guard.service.ts
import Injectable from '@angular/core';
import CanActivate, Router from '@angular/router';
import JwtHelperService from '@auth0/angular-jwt';
@Injectable(
providedIn: 'root'
)
export class AuthGuard implements CanActivate
constructor(private router: Router, private jwtHelper: JwtHelperService)
canActivate()
const token = localStorage.getItem("jwt");
if (token && !this.jwtHelper.isTokenExpired(token))
return true;
this.router.navigate(["login"]);
return false;
登录组件工作
@组件( 选择器:'应用程序登录', templateUrl: './login.component.html', styleUrls: ['./login.component.css'] ) 导出类登录组件 无效登录:布尔值;
constructor(private router: Router, private http: HttpClient)
login(form: NgForm)
const credentials = JSON.stringify(form.value);
this.http.post("https://localhost:44363/api/auth/login", credentials,
headers: new HttpHeaders(
"Content-Type": "application/json"
)
).subscribe(response =>
const token = (<any>response).token;
localStorage.setItem("jwt", token);
this.invalidLogin = false;
this.router.navigate(["/"]);
, err =>
this.invalidLogin = true;
);
这是我的 app.module
export function tokenGetter()
return localStorage.getItem("jwt");
@NgModule(
declarations: [
AppComponent,
NavMenuComponent,
HomeComponent,
CounterComponent,
FetchDataComponent,
LocationManagerComponent,
ClientsComponent,
ClientDetailsComponent,
LoginComponent
],
imports: [
BrowserModule.withServerTransition( appId: 'ng-cli-universal' ),
DataTablesModule,
HttpClientModule,
FormsModule,
RouterModule.forRoot([
path: '', component: HomeComponent, pathMatch: 'full' ,
path: 'counter', component: CounterComponent ,
path: 'fetch-data', component: FetchDataComponent ,
path: 'location-manager', component: LocationManagerComponent ,
path: 'clients', component: ClientsComponent, canActivate: [AuthGuard] ,
path: 'clients/:clientId', component: ClientDetailsComponent, canActivate: [AuthGuard] ,
path: 'login', component: LoginComponent ,
]),
BrowserAnimationsModule,
JwtModule.forRoot(
config:
tokenGetter: tokenGetter,
whitelistedDomains: ["localhost:44363"],
blacklistedRoutes: []
)
],
providers: [AuthGuard],
bootstrap: [AppComponent]
)
export class AppModule
Finnaly 这里是导致我的问题的文件。当我尝试从我的 api 获取客户端时,我的浏览器中出现 401。
@Component(
selector: 'app-clients',
templateUrl: './clients.component.html',
styleUrls: ['./clients.component.css']
)
export class ClientsComponent implements OnInit
dtOptions: DataTables.Settings = ;
public clients: Client[];
constructor(private http: HttpClient)
ngOnInit(): void
this.dtOptions =
pagingType: 'full_numbers',
pageLength: 10,
processing: true
;
this.http.get<Client[]>('https://localhost:44363/api/clients',
headers: new HttpHeaders(
"Content-Type": "application/json"
)
).subscribe(result =>
this.clients = result;
, error =>
console.log(error)
);
onSubmit(closet: any, drawer: any)
//get the value by its property
console.log("Closet: " + closet);
console.log("Drawer: " + drawer);
这里是相关的 csharp 文件
在我的启动中,我对其进行了配置,以便使用 angular 并使用 jwt 键。
public class Startup
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.AddCors(options =>
options.AddPolicy("EnableCORS", builder =>
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
);
);
services.AddAuthentication(opt =>
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(opttions =>
opttions.TokenValidationParameters = new TokenValidationParameters
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = "https://localhost:44363",
ValidAudience = "https://localhost:44363",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("superSecretKey@45"))
;
);
services.AddControllersWithViews();
services.AddSpaStaticFiles(configuration =>
configuration.RootPath = "ClientApp/dist";
);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<DatabaseMigrator>();
services.AddDbContext<erp_colombiaDbContext>(options => options.Usemysql(
Configuration.GetConnectionString("DefaultConnection"),
optionsBuilder => optionsBuilder.MigrationsAssembly(typeof(DesignTimeDbContextFactory).Assembly.FullName)));
services.AddDbContext<erp_colombiaDbContext>(options => options.UseMySql(
Configuration.GetConnectionString("DefaultConnection"),
optionsBuilder => optionsBuilder.MigrationsAssembly(typeof(DesignTimeDbContextFactory).Assembly.FullName)));
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
app.UseExceptionHandler("/Error");
app.UseHsts();
app.UseHttpsRedirection();
app.UseCors("EnableCORS");
app.UseStaticFiles();
if (!env.IsDevelopment())
app.UseSpaStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
endpoints.MapControllerRoute(
name: "default",
pattern: "controller/action=Index/id?");
);
app.UseSpa(spa =>
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
spa.UseAngularCliServer(npmScript: "start");
);
这是我想从中获取客户端列表的控制器
// GET api/clients
[HttpGet]
[Authorize]
public IEnumerable<ClientViewModel> Get()
ClientViewModel clientViewModel;
List<ClientViewModel> listClientViewModels = new List<ClientViewModel>();
var clients = Task.Run(async () => await _clientService.GetAllClients()).Result;
foreach (var client in clients)
clientViewModel = new ClientViewModel();
clientViewModel.ClientId = client.ClientId;
clientViewModel.Active = client.Active;
clientViewModel.Address = client.Address;
clientViewModel.City = client.City;
clientViewModel.ClienteName = client.ClienteName;
clientViewModel.ComercialEmployeeId = client.ComercialEmployeeId;
clientViewModel.Confirmed = client.Confirmed;
clientViewModel.CountryId = client.CountryId;
clientViewModel.CreationDate = client.CreationDate;
clientViewModel.DANE = client.DANE;
clientViewModel.Department = client.Department;
clientViewModel.ElectronicBillingEmail = client.ElectronicBillingEmail;
clientViewModel.Eliminated = client.Eliminated;
clientViewModel.NIT = client.NIT;
clientViewModel.PostalCode = client.PostalCode;
clientViewModel.Phone = client.Phone;
listClientViewModels.Add(clientViewModel);
return listClientViewModels;
【问题讨论】:
【参考方案1】:如果我没记错你得到的是 401,因为你的请求不是 Authorized
。
因此,您只需将 Authorization
标头添加到您的请求中,例如:
headers: new HttpHeaders(
"Authorization": `Bearer $localStorage.getItem("jwt")`,
"Content-Type": "application/json"
)
但我强烈建议使用Interceptor
,它将为每个请求应用Authorization token
(一次定义,无需复制代码\标题等)
@Injectable()
export class ApplyJWTTokenInterceptor implements HttpInterceptor
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
const idToken = localStorage.getItem("jwt");
if (idToken)
const authClonedRequest = req.clone(
headers: req.headers
.set('Authorization', `Bearer $idToken`)
);
return next.handle(authClonedRequest);
else
return next.handle(req);
建议检查:
HTTPInterceptor Intercepting requests and responses Worked demo
【讨论】:
我不确定我应该在哪里创建类 ApplyJWTTokenInterceptor 我可以在 app 文件夹中直接创建文件吗?还有应该在哪里调用 ApplyJWTTokenInterceptor? 只需在提供程序中注入应用程序模块(另请查看推荐以获取更多信息和确切的示例项目) 我对使用不同的 HTTPInterceptor 很敏感。我将在我的问题中添加代码。 我相信 AuthGuard.service.ts 是我的 HTTpInterceptor? 那么 - 这取决于 .Net Core 部分 - 你必须找出设置有什么问题,然后这个问题不涉及角度。以上是关于即使使用 ASP.NET CORE 登录,我在 Angular 中也有 401 Unauthorized的主要内容,如果未能解决你的问题,请参考以下文章
如何在Asp.net Core的登录过程中为“记住我”设置单个cookie超时?
为啥我在 Asp.Net CORE 中使用 JWT 获得 401 未经授权?
ASP.NET Core 3.1 MVC JWT 登录返回 401