我正在尝试使用 ApiRest,但因为他们添加了令牌验证,所以我无法使用它。在他们添加该验证之前,如果我设法正确使用它。
由于必须发送令牌,因此我无法使用它。错误如下:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:8100'; is therefore not allowed access. Le agregué los HttpHeaders –
在 postman 中测试 API 时,它可以正常工作。
目前rest.ts文件如下:
import { HttpClient, HttpHeaderResponse, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { HttpHeaders } from '@angular/common/http';
/*
Generated class for the RestProvider provider.
See https://angular.io/guide/dependency-injection for more info on providers
and Angular DI.
*/
@Injectable()
export class RestProvider {
apiUrl = 'http://localhost:49533/api/Login';
constructor(public http: HttpClient) {
console.log('Hello RestProvider Provider');
}
logIn(username: string, password: string, pasword2: string) {
const url = 'http://localhost:49533/api/Login';
const body = JSON.stringify({
Codigo: username,
Usuario: password,
Password: pasword2
});
//let headers = new HttpHeaders();
const headers = new HttpHeaders().set("X-CustomHttpHeader", "CUSTOM_VALUE")
.set('Access-Control-Allow-Origin', '*')
.set('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, PUT')
.set('Accept', 'application/json')
.set('Content-Type', 'application/json; charset=utf-8');
this.http.post(url, body, { headers: headers }).subscribe(
(data) => {
console.log(data);
},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
console.log('Client-side error occured.');
} else {
console.log('Server-side error occured.');
}
}
);
}
/*getUsers() {
return new Promise(resolve => {
this.http.get(this.apiUrl + '/api/Login/123/123/123').subscribe(data => {
resolve(data);
console.log(data);
}, err => {
console.log(err);
});
});
}*/
addUser(data) {
return new Promise((resolve, reject) => {
this.http.post(this.apiUrl + '/users', JSON.stringify(data))
.subscribe(res => {
resolve(res);
}, (err) => {
reject(err);
});
});
}
}
我在哪里调用 getUsers():
import { RestProvider } from '../../providers/rest/rest';
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
users: any;
constructor(public navCtrl: NavController, public restProvider: RestProvider) {
this.logIn();
//this.getUsers();
}
logIn(){
this.restProvider.logIn("1234","1234","123123")
}
/*getUsers() {
this.restProvider.getUsers()
.then(data => {
this.users = data;
console.log(this.users);
});
}*/
}
在 C# 中检查 Rest API:
public class TokenValidationHandler : DelegatingHandler
{
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
}
我检查了它带有request.Headers.tryGetValues,它带有以下内容:
{Method: OPTIONS, RequestUri: 'http://localhost:49533/api/Login', Version: 1.1, Content: System.Web.Http.WebHost.HttpControllerHandler+LazyStreamContent, Headers:
{
Connection: keep-alive
Accept: */*
Accept-Encoding: gzip
Accept-
Encoding: deflate
Accept-Encoding: br
Accept-Language: es-ES
Accept-Language: es; q=0.9
Host: localhost:49533
User-Agent: Mozilla/5.0
User-Agent: (Linux; Android 5.0; SM-G900P Build/LRX21T)
User-Agent: AppleWebKit/537.36
User-Agent: (KHTML, like Gecko)
User-Agent: Chrome/69.0.3497.100
User-Agent: Mobile
User-Agent: Safari/537.36
Access-Control-Request-Method: POST
Origin: http://localhost:8100
Access-Control-Request-Headers: access-control-allow-methods,access-control-allow-origin,content-type
ApplicationInsights-RequestTrackingTelemetryModule-RootRequest-Id: 087a23b9-5473-47db-9b86-bb90f7a1cffa
}}
从那里开始,它不再发生在 Api 休息中。
完整的令牌验证处理程序:
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
namespace Ws
{
public class TokenValidationHandler : DelegatingHandler
{
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
return false;
}
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpStatusCode statusCode;
string token;
//determine whether a jwt exists or not
if (!TryRetrieveToken(request, out token))
{
statusCode = HttpStatusCode.Unauthorized;
//allow requests with no token - whether a action method needs an authentication can be set with the claimsauthorization attribute
return base.SendAsync(request, cancellationToken);
}
try
{
const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
var now = DateTime.UtcNow;
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
SecurityToken securityToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidAudience = "http://localhost:49533",
ValidIssuer = "http://localhost:49533",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
LifetimeValidator = this.LifetimeValidator,
IssuerSigningKey = securityKey,
ValidateAudience = false,
ValidateIssuer = false
};
//extract and assign the user of the jwt
Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);
return base.SendAsync(request, cancellationToken);
}
catch (SecurityTokenValidationException e)
{
statusCode = HttpStatusCode.Unauthorized;
}
catch (Exception ex)
{
statusCode = HttpStatusCode.InternalServerError;
}
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode) { });
}
public bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (expires != null)
{
if (DateTime.UtcNow < expires) return true;
}
return false;
}
}
}
实施@sioesi 的帮助:
ionic 项目运行在:http://localhost:8100/,其余的 api 在http://localhost:49533/
在这种情况下 ionic.config.json :
{
"name": "ionic3-angular43-rest",
"app_id": "",
"type": "ionic-angular",
"integrations": {},
"proxies": [
{
"path": "/api",
"proxyUrl": "http://localhost:49533"
}
]
}
和登录方法:
return this.http.post('/api/api/Login', body, { headers: headers }).subscribe(
(data) => {
console.log(data);
},
(err: HttpErrorResponse) => {
if (err.error instanceof Error) {
console.log('Client-side error occured.');
} else {
console.log('Server-side error occured.');
}
}
通过最后的更改,它可以正常工作。非常感谢您的帮助。
尝试在文件中实施
ionic.config.json
修复proxies
当您拨打电话时,您只需连接:
并且操作保持原样,当您使用您在 中定义的单词时
path
,它会自动理解它必须访问您定义的 url,并且调用将被执行,就好像它是从同一位置进行的一样。问题显然是 cors 而不是你的后端,这个答案只有在你在网络上测试时才有效,使用
ionic serve
, 从移动应用程序你不会有问题。