Nelmio_cors : error 400 when doing a POST to API - api

here is my problem. I have a front website on Angular 5 and a back API on Symfony 3.4.
I am using FOSRestBundle to make my API requests. When I try to do a POST request to my API, I got an error : "Failed to load http://127.0.0.1:8000/api/pro/login: Response for preflight has invalid HTTP status code 400."
Here are my different codes :
LoginController.php :
<?php
namespace ProBundle\Controller;
use FOS\RestBundle\Controller\Annotations as Rest;
use Proxies\__CG__\ProBundle\Entity\Utilisateur;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Response;
class LoginController extends Controller
{
/**
* #Rest\Post(
* path = "/api/pro/login",
* name = "dropnride_pro_login"
* )
* #Rest\View
* #ParamConverter("utilisateur", converter="fos_rest.request_body")
*/
public function loginAction(Utilisateur $utilisateur)
{
$response = new Response($utilisateur->loginToString());
return $response;
}
}
login.component.ts :
import { Component } from '#angular/core';
import { NgForm } from '#angular/forms';
import { LoginService } from '../services/login.service';
#Component({
selector: 'dropnride-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss'],
providers: [LoginService]
})
export class LoginComponent {
constructor(private _loginService: LoginService) { }
onSubmit(form: NgForm) {
const email = form.value['email'];
const password = form.value['password'];
this.askLogin(email, password);
}
askLogin(email: string, motDePasse: string) {
const userData = {
email: '',
motDePasse: '',
}
userData.email = email;
userData.motDePasse = motDePasse;
// Contact de l'API
this._loginService.getLoginData(userData);
}
}
login.service.ts :
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
const loginUrl = "http://127.0.0.1:8000/api/pro/login";
#Injectable()
export class LoginService {
constructor(private http: HttpClient) {
}
getLoginData(userData) {
const headers = new HttpHeaders({
'Content-Type': 'application/json'
});
console.log(userData);
return this.http.post(loginUrl, userData, {headers: headers}).subscribe(data => {
console.log(data);
});
}
}
My API calls works well with Postman :
API call through Postman
I have installed and configured NelmioCorsBundle in my config.yml :
nelmio_cors:
defaults:
allow_credentials: false
allow_origin: ['*']
allow_headers: ['*']
allow_methods: []
expose_headers: []
max_age: 0
hosts: []
origin_regex: false
forced_allow_origin_value: ~
paths:
'^/api/':
allow_origin: ['*']
allow_headers: ['X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
max_age: 3600
'^/':
origin_regex: true
allow_origin: ['^http://localhost:[0-9]+']
allow_headers: ['X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
max_age: 3600
hosts: ['^api\.']
I've nearly tried all of the other stackoverflow's members proposal for similar problems, I couldn't find a solution working for me... Would you have any idea that would help me with my problem ? Thanks a lot in advance :)

Try setting Content-Type too as allowed header
allow_headers: ['X-Custom-Auth', 'Content-Type]
And allow 'OPTIONS' (not sure if it's actually needed)
allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTIONS']

Related

Angular Login issue

I am new in Angular 7. I am working in a Angular 7 project. I have a login component like below
import { Component, OnInit } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { TokenService } from '../../token.service'
import { Router, ActivatedRoute } from '#angular/router';
import { ServerService } from 'src/app/server.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
response: any;
failmsg: boolean = false;
constructor(private http: HttpClient,
private server: ServerService,
private Token: TokenService,
private router: Router,
private _router: ActivatedRoute
) { }
public form = {
grant_type: 'password',
client_id: 2,
client_secret: 'W5nQYuW1OFknDwiDnU96Y7dBMqTJ5jG6r6AXYk9q',
username: null,
password: null
}
headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.handleResponse2()
});
login() {
this.http.post(this.server.base_url + "login", this.form).subscribe( //execution is not entering inside this block
(data) => {
this.handleResponse(data);
this.http.get(this.server.base_url + "employees/employee/user/profile", { headers: this.headers }).subscribe(
(profile) => {
this.employeeProfile = profile;
if (this.employeeProfile.user_id == 1) {
this.router.navigate([this._router.snapshot.paramMap.get("portal") + '/home/dashboard'])
.then(rel => location.reload());
} else {
localStorage.setItem('employeeId', this.employeeProfile.employeeId);
localStorage.setItem('id', this.employeeProfile.id);
this.router.navigate([this._router.snapshot.paramMap.get("portal") + '/home/employee-dashboard'])
.then(rel => location.reload());
}
}
)
},
(error) => { //execution is entering inside this block
console.log('hello');
if (error) {
this.failmsg = true;
}
console.log(error);
}
);
}
employeeProfile: any;
handleResponse(data) {
this.Token.set(data.access_token);
this.headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.handleResponse2()
});
}
onClose() {}
handleResponse2() {
return this.Token.get();
}
ngOnInit() {
localStorage.setItem('portal', this._router.snapshot.paramMap.get("portal"));
this.server.set_base_url(this._router.snapshot.paramMap.get("portal"));
this.server.set_base_url2(this._router.snapshot.paramMap.get("portal"));
}
}
I can't login. I am getting error like below
My network tab is like below
Could anyone help me to fix this issue ?
Your target in proxy.conf should be http://alasr.com not localhost:4200.
What happen is --proxy-config option will treat http://alasr.com as though it is running on the same port as ur angular which is localhost:4200. So there will be no Cross Origin problem.
Btw, u can use npm 'start' script to give the proxy.conf file to the --proxy-config option
You are not able to hit the backend endpoints because of CORS- Cross origin resource sharing issue. You can check this link for more info: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
To fix this issue in angular you need to use --proxy-config option with your ng serve command. First, you need to create a JSON file proxy.conf.json and add below content:
{
"/al-asr": {
"target": "http://alasr.com",
"secure": false
}
}
I am assuming, Your backend is running in url http://alasr.com and url base is /al-asr.
Also in your httpClient pass the url like this
this.http.get('/al-asar/api/in/v1/employees/employee/user/profile')
Now run the server with below command to fix this issue:
ng serve --proxy-config proxy.conf.json
Try this
{
"/api": {
"target": "https://9c8c4aa0.ngrok.io",
"secure": true,
"changeOrigin": true,
"logLevel": "debug"
}
}

Unable to send data in headers to authorize the request in php

I am getting the error message in cli like :
Type 'Headers' has no properties in common with type 'RequestOptionsArgs'
. However, the code executes. The version I am using is 5, as it shows in package.json. I am unable to find a good http example, which suit my need. I want to send some parameters in headers section, and authorize it in php. Here is the service code:
user.service.ts
import { Observable } from 'rxjs/Observable';
import { Customer } from './../models/customer';
import { Injectable } from "#angular/core";
import { Http, Response, Headers, RequestOptions } from "#angular/http";
import "rxjs/add/operator/map";
import { apiServicesURL,appServicesURL } from "../constants/globals";
import { HttpClient, HttpHeaders } from "#angular/common/http";
#Injectable()
export class UserService {
//headers : Headers ;
constructor(private http: Http) {
}
getCustomerInfoo(custId): Observable<Customer> {
//cust.push({token : localStorage.getItem('token')});
console.log(apiServicesURL + 'getCustomers');
let token = localStorage.getItem('token');
let api_token = localStorage.getItem('api_token');
let email = localStorage.getItem('email');
let headers = new Headers({ 'Content-Type': 'application/json' });
// let options: RequestOptions = new RequestOptions({ headers: headers });
return this.http.post(apiServicesURL + 'getCustomers', JSON.stringify({ customer_id: custId, token: api_token, email: email }), headers ).map((response: Response) => {
// login successful if there's a jwt token in the response
return <Customer>response.json();
});
}
}
Any help, appreciated!!!
If you are using angular 5 then try it this below code and write RequestOptionsProvider to module.ts file
import { Injectable } from '#angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HTTP_INTERCEPTORS } from '#angular/common/http';
import { AuthService } from '#app/core/services/auth.service';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class DefaultRequestOptionsService implements HttpInterceptor {
constructor(private auth: AuthService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get the auth header from the service.
// const authHeader = this.auth.getAuthorizationHeader();
// Clone the request to add the new header.
// const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
const authReq = req.clone({ headers: req.headers.set('Content-Type', 'application/json') });
// Pass on the cloned request instead of the original request.
return next.handle(authReq);
}
}
export const RequestOptionsProvider = { provide: HTTP_INTERCEPTORS, useClass: DefaultRequestOptionsService, multi: true };

HttpClient issue in angular5

I am working with Angular 4 with HttpService, i am trying to migrate to HttpClientService.
but i am getting the error as below
ERROR in src/app/app.service.ts(19,102): error TS2559: Type 'Headers' has no properties in common with type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
please refer my app.service.ts also
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { map, catchError } from 'rxjs/operators';
#Injectable()
export class AppService {
// tslint:disable-next-line:max-line-length
private token: any = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjYxMmMyMDEyNmI1ZTY1ZGE3NWE3YmQ3MmJlNGYzMDIzYWZ5a9';
public headers = new Headers({
'Content-type': 'application/json',
'Authorization' : `Bearer ${this.token}`
});
constructor(private http: HttpClient) { }
getData() {
return this.http.get('http://192.111.99.**/cloudnew/public/api/generic/registrations/view/0', this.headers);
}
}
Based on the comment below.... I would suggest implementing Http interceptors.... something like this....
You first need an authentication service that grabs the token at first, then you can store the token ad send it with each request with interceptors..
import { Inject, Injectable, Optional, OnInit, OnDestroy } from '#angular/core';
import { HttpClient, HttpHeaders, HttpResponse, HttpErrorResponse } from '#angular/common/http';
import { Observable, Subject, Subscription } from 'rxjs';
import * as moment from 'moment';
#Injectable()
export class AuthService implements OnInit, OnDestroy {
subscriptions: Subscription[] = [];
constructor(private http: HttpClient) {}
ngOnInit() {
this.subscriptions.push(this.login().subscribe(res=> this.handleLogin(res)));
}
ngOnDestroy() {
this.subscriptions.forEach(s=> s.unsubscribe());
}
getBaseHeader(): HttpHeaders {
const header = new HttpHeaders({
'Content-Type': 'application/json'
});
return header;
}
getAuthHeaders(): HttpHeaders {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': this.token
});
return headers;
}
getHeaders(): HttpHeaders {
if(this.token && this.validateToken()) {
return this.getAuthHeaders();
} else {
return this.getBaseHeader();
}
}
storeLogin(response: Response) {
.... store login token etc...
}
getStoredLogin(): any {
... get login/token etc...
}
getToken(): string {
return this.token;
}
login(): Observable<Response> {
const headers = new Headers({'Content-Type': 'application/json'});
const options = new RequestOptions({headers: headers});
return this.http.post(path, { body to be sent ie login password }, options);
}
loggedIn(): boolean {
return ....login crentials | false/null;
}
validateToken() {
return moment(this.tokenExpiration).isAfter(moment().second());
}
handleError(err: Response, fn?: string) {
console.log(typeof err);
if(fn) console.log(fn);
console.log(err.toString());
}
}
then the interceptor......
import { Injectable, Injector } from '#angular/core';
import { HttpEvent, HttpHandler, HttpRequest, HttpInterceptor } from '#angular/common/http';
import { Observable } from 'rxjs/Observable';
import { AuthService } from '../../services/auth.service';
#Injectable()
export class ApiInterceptor implements HttpInterceptor {
constructor(private inj: Injector) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let authService = this.inj.get(AuthService);
const authHeader = authService.getHeaders();
const authReq = req.clone({headers: authHeader});
return next.handle(authReq);
}
}
This way you the interceptors do all the work for you after the initil login. Simplified the code to more of a shell than a snippet of a working application

Adding headers via HttpInterceptor Angular 5

I want to add headers to post request from Angular 5 web app.
I've created the following Injectable class, registered in my app module:
#Injectable()
export class headerInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Clone the request to add the new header
const authReq = req.clone({
headers: new HttpHeaders({
'Content-Type': 'application/json; charset=utf-8',
})
});
return next.handle(authReq);
}
}
I have network communication service and Im adding body parameters as below.
#Injectable()
export class NetworkService {
Root:string = 'some valid url';
results:Object[];
loading:boolean;
// inject Http client to our client service.
constructor(private httpClient: HttpClient ) {
}
login(loginParams : URLSearchParams){
let baseURL = `${this.Root}/login`;
this.httpClient.post(baseURL, JSON.stringify({'UserName':'123','Password':'123'} ))
.subscribe(data => {
console.log();
},
err => {
console.log('Error: ' + err.error);
});
when I put breakpoint after the clone method inside headerInterceptor class I can see the request body.
the problem is when I switch to network tab in chrome, I get 405 error and I can't see the body and the new headers. when I return the original request 'req'
the body sent ok but no new headers of course.
App Module,
import { HttpClientModule, HTTP_INTERCEPTORS } from '#angular/common/http';
import { headerInterceptor } from './httpinterceptor'
Add it to providers,
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: headerInterceptor,
multi: true
}
],
Now change the intereptor to, I have changed the way headers are added
#Injectable()
export class headerInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const authReq = req.clone({
headers:req.headers.set("Content-Type", "application/json; charset=utf-8")
});
return next.handle(authReq);
}
}
}
You can also use setHeaders:
#Injectable()
export class headerInterceptor implements HttpInterceptor {
constructor() {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {y
req = req.clone({
setHeaders: {
"Content-Type": "application/json; charset=utf-8"
}
});
return next.handle(req);
}
}
My problem was on server side I'm using ASP.net and wcf.
it seems that the server must implement CORS support when working with Angular 5 project (works ok with jQuery and cross domain tag).
this post helped me to add support in CORS:
http://blogs.microsoft.co.il/idof/2011/07/02/cross-origin-resource-sharing-cors-and-wcf/

Ember-cli-simple-auth-devise :Authorization: Token token="<user_token>", user_email="<user_email>" (Header not added)

The 'Authorization' header is not being set for some reason.
I have tried setting the authorizer in
config/environment.js with
updated:as per #marcoow suggestion
ENV['simple-auth'] = {
crossOriginWhitelist: ['*'],
authorizer: 'simple-auth-authorizer:devise'
};
ENV['simple-auth-devise'] = {
serverTokenEndpoint: 'users/sign_in',
};
...I am able to login to my application by for updating other resources like post Authorization: Token token="", user_email="" is not getting added to my sever call
controller/dashboard.js
import Ember from 'ember';
export
default Ember.Controller.extend({
actions: {
add: function () {
var name = this.get('name');
var start = this.get('Start');
var end = this.get('End');
var game = this.store.createRecord('game', {
name: name,
start: start,
end: end
});
game.save();
}
}
});
my request looks something like this
**1. MY under standing is that the request headers here should contain
Authorization: header too.
I am using rack-cors gem to enable cors
I looked into source of ember-simple-auth-devise / lib / simple-auth-devise / authorizers / devise.js. the authorize: function() add this to request. I am not sure how to call this method.
login controller
import Ember from 'ember';
import LoginControllerMixin from 'simple-auth/mixins/login-controller-mixin';
export
default Ember.Controller.extend(LoginControllerMixin, {
authenticator: 'simple-auth-authenticator:devise',
actions: {
authenticate: function () {
console.log('i was called');
var self = this;
var data = this.getProperties('identification', 'password');
self.get('session').authenticate(this.get('authenticator'), data).then(function () {
self.transitionToRoute('dashboard');
}, function (error) {
console.log(error);
});
}
}
});
I can see:
How can i authorize my Model#save with devise....using ember-data
just for debugging i did this in route/dashboard.js
import Ember from 'ember';
import AuthenticatedRouteMixin from 'simple-auth/mixins/authenticated-route-mixin';
export default Ember.Route.extend(AuthenticatedRouteMixin,{
model: function() {
console.log(this.get('session.isAuthenticated')); # this is true
}
});
crossOriginWhitelist is not a property of the Devise package - you need to configure that for the Ember Simple Auth base package:
ENV['simple-auth'] = {
crossOriginWhitelist: ['*']
};
ENV['simple-auth-devise'] = {
serverTokenEndpoint: 'users/sign_in',
authorizer: 'authorizer:devise'
};
Have the same problem, my Authorization Header not added, too. My problem due to the response from Rails authenticate. In ember-simple-auth, I set identificationAttributeName to "username", but the json response from Rails authenticate("sessions#create" action) is like this: { token: 'xxxxx', user_email: 'xxxx' }, without a "username" field!
Solved by remove "user_email" field from session create action's response, add "username" field. Hope this will be helpful.