Implement Http Headers in Ionic-Angular Project (Enable Cors in Api Rest)

1

I am trying to consume an ApiRest, but because they added a token validation, I can not consume it. Before they added that validation, if it managed to consume it correctly.

As you have to send the token, I can not consume it. The error is as follows:

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 –

When testing the Api in postman, if it works correctly.

Currently the file rest.ts is in the following way:

            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);
            });
        });
      }
    }

Where I call 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);
    });
  }*/
}

When reviewing the Api Rest in C #:

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;
        }
}

I checked that it carries the request.Headers.tryGetValues and it carries the following:

  {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
}}

And then it does not happen anymore in the Api rest.

The complete validation handler token:

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;
        }
    }
}

Implementing the help of @sioesi:

The ionic project runs on: link and the api rest on link

In this case the ionic.config.json:

{
  "name": "ionic3-angular43-rest",
  "app_id": "",
  "type": "ionic-angular",
  "integrations": {},
  "proxies": [
    {
      "path": "/api", 
      "proxyUrl": "http://localhost:49533"
    }
  ]
}

and the login method:

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.');
        }
      }

With this last change, it worked correctly. Thank you very much for your help.

    
asked by raintrooper 02.10.2018 в 19:55
source

1 answer

3

Try to implement the ionic.config.json fix in the file proxies

"proxies": [
 {
  "path": "/api", //por ejemplo
  "proxyUrl": "http://tu_url"
 }
],

And when you make the call just concatenate:

"/api/tu_servicio/"

And the operation is still as you have it, by using the word you define in path , automatically understand that you must access the url you define and the call will be executed as if it were from the same location.

The problem is clearly the cors and not your backend, this answer works only when you test in a web, with a ionic serve , from the mobile application you will not have problems.

    
answered by 03.10.2018 / 19:00
source