Ionic2 / Angular 2 - Wordpress generate cookie auth from from app - wordpress

I am trying to generate a cookie auth from an ionic app as a front-end, and Wordpress as back-end (I'm using this JSON API USER plugin).
The first step is to generate the nonce : MYURLBASE/api/get_nonce/?controller=user&method=generate_auth_cookie
Then generate cookie: MYURLBASE/api/user/generate_auth_cookie/?nonce=375034fjwfn39u8&username=john&passsword=PASSWORD-HERE
I can get the nonce, but I'm having trouble building the service handling the request.
Here is my login.html:
<form [ngFormModel]="loginForm" (submit)="login(username, password)" style="padding-top: 50px">
<ion-list>
<ion-item>
<ion-label stacked-label>Nom d'utilisateur ou Email</ion-label>
<ion-input type="text" [(ngFormControl)]="username" value=""></ion-input>
</ion-item>
<ion-item>
<ion-label stacked-label>Mot de passe</ion-label>
<ion-input type="password" [(ngFormControl)]="password" value=""></ion-input>
</ion-item>
</ion-list>
<div>
<button block type="submit">Connexion</button>
</div>
</form>
This is my login.ts:
import {Page, NavController, Alert} from 'ionic-angular';
import { FORM_DIRECTIVES, FormBuilder, ControlGroup, Validators, AbstractControl, Control } from 'angular2/common';
import { Http, Headers, RequestOptions, Request, RequestMethod, Response } from 'angular2/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
import {LoginService} from './login.service';
import {WooPage} from '../woo/woo';
#Page({
templateUrl: 'build/pages/ecommerce/login/login.html',
providers:[LoginService],
})
export class LoginPage {
loginForm: ControlGroup;
username: AbstractControl;
password: AbstractControl;
response;
constructor(private loginService:LoginService, public nav: NavController,
fb: FormBuilder){
this.loginForm = fb.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
this.username = this.loginForm.controls['username'],
this.password = this.loginForm.controls['password']
}
// For test purposes
getNonce() {
this.loginService.getNonce()
.subscribe(
response => this.response = response,
error => console.log(error));
}
// For test purposes
generateCookie() {
this.loginService.generateCookie(this.loginService.getNonce())
.subscribe(
response => this.response = response,
error => console.log(error));
}
login(
username:string,
password:string) :void {
this.loginService.login(
username = this.username.value,
password = this.password.value
)
.subscribe(
response => this.response = response,
error => console.log(error)
);
}
}
And finally my login.service.ts:
import {Injectable,Inject} from 'angular2/core';
import {Http,Headers,Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import {NavController, Alert} from 'ionic-angular';
#Injectable()
export class LoginService {
private nonceUrl = 'https://MYURL/api/get_nonce/?controller=user&method=generate_auth_cookie'
private cookieUrlBase = 'https://MYURL/api/user/generate_auth_cookie/?nonce='
constructor(private http:Http) {}
getNonce() {
let nonce = this.http.get(this.nonceUrl).map(res => res.json().nonce);
return nonce;
}
generateCookie(nonce) {
return this.http.get(this.cookieUrlBase+nonce+'&username='+'chuckNorris'+'&password='+'chuckchuck')
}
// TODO: login(
// username: string,
// password: string):Observable<any> {
//
// const body = JSON.stringify(username + password);
// let headers = new Headers();
//
// headers.append('Content-Type', 'application/x-www-form-urlencoded');
// return this.http.post(, body, {
// headers : headers
// }).map(res => res.json());
// }
}
When I call the generateCookie function, I get the following url generated:
https://MYURL/api/user/generate_auth_cookie/?nonce=[object%20Object]&username=chuckNorris&password=chuckchuck
How can I pass the nonce value, as not to be an object?
Is there a better way to achieve the login authentification?
Thanks for the help, as I'm pretty lost here...
Yin.

try with:
getNonce() {
return new Promise(resolve => {
this.http.get(this.nonceUrl)
.map(res => res.json())
.subscribe(data => {
console.log(data);
});
});
}
Then, the result is something like:
{"status":"ok","controller":"user","method":"generate_auth_cookie","nonce":"66e6054397"}
So, then pass only the "nonce" property and not the entire object: result.nonce
this.cookieUrlBase+result.nonce+'&username='+'chuckNorris'+'&password='+'chuckchuck'

Related

REST API auth error : WooCommerce

Been trying to fetch products from WooCommerce REST API now forever and my brain is bleeding :'( I followed all instructions on woocommerce and github/woocommerce and I can't for my life get anything in Postman with Basic Auth:
But when I select Auth 1.0 - I get all products:
But then if I take the Auth 1.0 generated URL and put it in my browser:
..Instructions under Authentication over HTTP (here) describes the parameters which are generated in URL automatically when i select Auth 1.0 in Postman - but how am I gonna generate those in my React component?
const APP_URL = 'http://0.0.0.0:80'
const CONSUMER_KEY = 'ck_xxxx'
const CONSUMER_SECRET = 'cs_xxxx'
const PRODUCT_URL = `${APP_URL}/wp-json/wc/v2/products?consumer_key=${CONSUMER_KEY}&consumer_secret=${CONSUMER_SECRET}`
fetch(PRODUCT_URL).then(res => {
if(res.status === 200){
return json
} else {
console.log("ERROR RESPONSE STATUS: " + status);
}
}).then( json => {
console.log(json)
})
})
So thankful for all input!
I think this problem may be solved by below code using "Interceptor" concept...
import {
Injectable,
// Injector
} from '#angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
HttpErrorResponse
} from '#angular/common/http';
// import { Router } from '#angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
// import { AuthService } from './auth.service';
import { config } from '../config/config';
#Injectable()
export class AppInterceptor implements HttpInterceptor {
constructor(
// private injector: Injector,
// private router: Router
) { }
private includeWooAuth(url) {
const wooAuth = `consumer_key=${config.consumerKey}&consumer_secret=${config.secretKey}`;
const hasQuery = url.includes('?');
let return_url = '';
if (hasQuery) {
return_url = wooAuth;
} else {
return_url = '?' + wooAuth;
}
return return_url;
}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// const auth = this.injector.get(AuthService);
const authRequest = request.clone({
setHeaders: {
// Authorization: `Bearer ${auth.getToken()}`
},
url: `${config.basePath}/${request.url}${this.includeWooAuth(request.url)}`
});
return next.handle(authRequest)
.catch(err => {
if (err instanceof HttpErrorResponse && err.status === 0) {
console.log('Check Your Internet Connection And Try again Later');
} else if (err instanceof HttpErrorResponse && err.status === 401) {
// auth.setToken(null);
// this.router.navigate(['/', 'login']);
}
return Observable.throw(err);
});
}
}
This code will be kept into http.interceptor.ts. Obviously, you should initialize the consumer key and other details of woocommerce API into a constant variable. After that you create a service for show the list of the product like this:
retriveProducts(query: ProductQuery = {}): Observable<RetriveProductsResponse> {
return this.httpClient.get(`products`, {params: this.wooHelper.includeQuery(query), observe: 'response'})
.pipe(
map(value => this.wooHelper.includeResponseHeader(value)),
catchError(err => this.wooHelper.handleError(err)));
}
And call this service to the product.ts file like this:
getProducts() {
this.woocommerceProductsService.retriveProducts()
.subscribe(productResponse => {
this.products = productResponse.products;
}, error => this.errorMessage = <any>error);
}
I have used these above code into my project. I think it will help you.

Post call method in ionic2

New to ionic2 want to know what is post method , where to use, where to write a code???
Here is the sample code
//ts code
constructor(public formBuilder: FormBuilder,
) {
this.signupForm = formBuilder.group({
firstName: ['', Validators.compose([Validators.maxLength(20), Validators.pattern('[a-zA-Z ]*'), Validators.required])]
});
//html code
<form [formGroup]="signupForm">
<ion-item>
<ion-label floating>FIRST NAME</ion-label>
<ion-input formControlName="firstName" type="text"></ion-input>
</ion-item>
</form>
-- want to post the signupForm!!
Well, let's keep it short for basic understanding of post method.
import { Http } from '#angular/http'; import { Observable } from 'rxjs';
then
doPost(someData: any): Observable<any> {
this.http.post('auth/login').map(response => {
return response.json();
});
}
then you call it with
doPost(myData).subscribe(response => console.log(response));

Extend http on dont call request method in Angular 2

I new in Angular 2 and i'm trying create an App with JWT. So, to do this I follow the post http://www.adonespitogo.com/articles/angular-2-extending-http-provider/.
But i'm a issue, the request method is never call, after login i have to refresh the page to send the token.
Here my classes
http.service.ts
import { Injectable } from '#angular/core';
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
#Injectable()
export class HttpService extends Http {
constructor (backend: XHRBackend, options: RequestOptions) {
let token = localStorage.getItem('auth_token'); // your custom token getter function here
options.headers.set('Authorization', `Bearer ${token}`);
options.headers.append('Content-Type', 'application/json');
super(backend, options);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
let token = localStorage.getItem('auth_token');
if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
if (!options) {
// let's make option object
options = {headers: new Headers()};
}
options.headers.set('Authorization', `Bearer ${token}`);
options.headers.append('Content-Type', 'application/json');
} else {
// we have to add the token to the url object
url.headers.set('Authorization', `Bearer ${token}`);
url.headers.append('Content-Type', 'application/json');
}
return super.request(url, options)
.catch(this.catchAuthError(this));
}
private catchAuthError (self: HttpService) {
// we have to pass HttpService's own instance here as `self`
return (res: Response) => {
console.log(res);
if (res.status === 401 || res.status === 403) {
// if not authenticated
console.log(res);
}
return Observable.throw(res);
};
}
}
app.module.ts
providers: [{
provide: HttpService,
useFactory: (backend: XHRBackend, options: RequestOptions) => {
return new HttpService(backend, options);
},
deps: [XHRBackend, RequestOptions]
}, LoggedInGuard, UserService],
picture.service.ts
#Injectable()
export class PictureService {
url: string = 'v1/pictures';
constructor(private http: HttpService) { }
list(): Observable<PictureComponent[]> {
return this.http
.get(this.url)
.map(res => res.json());
}
}
Component to consume picture.service.ts
#Component({
moduleId: module.id,
selector: 'picture-list',
templateUrl: './pictureList.component.html'
})
export class ListagemComponent {
pictures: PictureComponent[] = [];
service: PictureService;
msg: String = '';
constructor(service: PictureService){
this.service = service;
this.service
.list()
.subscribe(pictures => {
this.pictures = pictures;
}, err => console.log(err));
}
}
thanks for help
Did you provide picture.service in your module? If not, you should provide it in your #component or in your module if you want it globally.
I extend XHRBackend
import { Injectable } from '#angular/core';
import { Request, XHRBackend, BrowserXhr, ResponseOptions, XSRFStrategy, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw';
#Injectable()
export class ExtendedXHRBackend extends XHRBackend {
constructor(browserXhr: BrowserXhr, baseResponseOptions: ResponseOptions, xsrfStrategy: XSRFStrategy) {
super(browserXhr, baseResponseOptions, xsrfStrategy);
}
createConnection(request: Request) {
let token = localStorage.getItem('token');
request.headers.set('x-access-token', `${token}`);
request.headers.set('Content-Type', 'application/json');
let xhrConnection = super.createConnection(request);
xhrConnection.response = xhrConnection.response.catch((error: Response) => {
if (error.status === 401 || error.status === 403) {
console.log('access not alowed');
localStorage.removeItem('token');
}
return Observable.throw(error);
});
return xhrConnection;
}
}
and use on app module
providers: [{ provide: XHRBackend, useClass: ExtendedXHRBackend }]
After this I resolve the issue and works preety well

Angular2 http subscribe component

An angular2 app, try to register an email.
import {Component, Directive, provide, Host} from '#angular/core';
import {NG_VALIDATORS, NgForm} from '#angular/forms';
import {ChangeDetectorRef, ChangeDetectionStrategy} from '#angular/core';
import {ApiService} from '../../services/api.service';
import {actions} from '../../common/actions';
import {EmailValidator} from '../../directives/email-validater.directive';
import * as _ from 'lodash';
import * as Rx from 'rxjs';
#Component({
selector: 'register-step1',
directives: [EmailValidator],
styleUrls: ['app/components/register-step1/register.step1.css'],
templateUrl: 'app/components/register-step1/register.step1.html'
})
export class RegisterStep1 {
email: string;
userType: number;
errorMessage: string;
successMessage: string;
constructor(private _api: ApiService, private ref: ChangeDetectorRef) {
this.successMessage = 'success';
this.errorMessage = 'error';
}
submit() {
var params = {
email: this.email,
type: +this.userType
};
params = {
email: '1#qq.com',
type: 3
};
this._api.query(actions.register_email, params).subscribe({
next: function(data) {
if(data.status) {
console.log("success register");
this.successMessage = "ok ,success";
console.log(this.errorMessage, this.successMessage);
}else{
this.errorMessage = data.message;
console.warn(data.message)
}
},
error: err => console.log(err),
complete: () => console.log('done')
});
}
}
my ApiService is simple:
import {Injectable} from '#angular/core';
import {Http, Headers, RequestOptions} from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import {AjaxCreationMethod, AjaxObservable} from 'rxjs/observable/dom/AjaxObservable';
import {logError} from '../services/log.service';
import {AuthHttp, AuthConfig, AUTH_PROVIDERS} from 'angular2-jwt';
#Injectable()
export class ApiService {
_jwt_token:string;
constructor(private http:Http) {
}
toParams(paramObj) {
let arr = [];
for(var key in paramObj) {
arr.push(key + '=' + paramObj[key]);
}
return arr.join('&')
}
query(url:string, paramObj:any) {
let headers = new Headers({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'});
let options = new RequestOptions({headers: headers});
return this.http.post(url, this.toParams(paramObj), options).map(res=>res.json())
}
}
this is my html :
<form #f="ngForm">
usertype<input type="text" name="userType" [(ngModel)]="userType"><br/>
<input type="text" name="email" ngControl="email" email-input required [(ngModel)]="email">
<button [disabled]="!f.form.valid" (click)="submit(f.email, f.userType)">add</button>
</form>
{{f.form.errors}}
<span *ngIf="errorMessage">error message: {{errorMessage}}</span>
<span *ngIf="successMessage">success message: {{successMessage}}</span>
I can success send the api to server and received response, I subscribe an observer to the http response which is a Observable object, inner the next function, I console.log() my successMessage, but i got 'undefined', and when I change the successMessage my html has no change.
It seems like I have lost the scope of my component, then I can't use this keyword
That's because you use the function keyword inside TypeScript. Never do this. Always use the arrow notation () => {}.
You should change your next function to:
next: (data) => {
if(data.status) {
console.log("success register");
this.successMessage = "ok ,success";
console.log(this.errorMessage, this.successMessage);
}else{
this.errorMessage = data.message;
console.warn(data.message)
}

Data communication in Angular2

I'trying to use the HTTP service in Angular2 and i have some concerns.
I'm taking meteo datas from openweather API and I just want to put it inside a typeScript variable (meteo: {}) and use it as i want in my template.
Here are my .ts files:
meteo.service.ts
import {Injectable} from "angular2/core";
import {Http, Response} from "angular2/http";
import {Observable} from "rxjs/Observable";
import {MeteoComponent} from "../widgets/meteo/meteo.component";
import {Meteo} from "../widgets/meteo/meteo";
#Injectable()
export class MeteoService {
constructor(private http: Http) {}
// Nom de la ville sans accent
private _ville = 'Montreal';
// Initiales du pays
private _country = 'ca';
// Units (metric/imperial)
private _units = 'metric';
// API KEY
private _APPID = 'ewfw54f5646';
// url to get data
private _meteoUrl = 'http://api.openweathermap.org/data/2.5/weather?q='+this._ville+','+this._country+'&units='+this._units+'&APPID='+this._APPID;
getMeteo (): Observable<Meteo> {
return this.http.get(this._meteoUrl)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
if(res.status < 200 || res.status >= 300) {
throw new Error('Bad response status: ' + res.status);
}
let body = res.json();
return body || { };
}
private handleError(error: any) {
let errMsg = error.message || 'server error';
console.error(errMsg);
return Observable.throw(errMsg);
}
}
meteo.component.ts
import {Component, OnInit, OnChanges, AfterContentInit} from "angular2/core";
import {MeteoService} from "../../services/meteo.service";
import {Meteo} from "./meteo";
#Component({
selector: 'meteo',
templateUrl: 'dev/widgets/meteo/meteo.component.html',
providers: [MeteoService]
})
export class MeteoComponent implements OnInit {
errorMessage: string;
meteo: Meteo;
// We inject the service into the constructor
constructor (private _meteoService: MeteoService) {}
// Instantiate data in the ngOnInit function to keep the constructor simple
ngOnInit() {
this.getMeteo();
}
getMeteo() {
this._meteoService.getMeteo()
.subscribe(
data => this.meteo = data,
error => this.errorMessage = <any>error);
}
}
meteo.ts
export class Meteo {
data: {};
}
and meteo.component.html
<span class="meteo">{{meteo | json}}°C</span>
Actually the result is the entire json object:
{
"coord": {
"lon":-73.59,
"lat":45.51
},
"weather":[
{
"id":803,
"main":"Clouds",
"description":"broken clouds",
"icon":"04d"
}
],
"base":"cmc stations",
"main":{
"temp":3.96,
"pressure":1020,
"humidity":32,
"temp_min":2,
"temp_max":6.67
},
"wind":{
"speed":2.1
},
"clouds":{
"all":75
},
"dt":1461594860,
"sys":{
"type":1,
"id":3829,
"message":0.004,
"country":"CA",
"sunrise":1461577807,
"sunset":1461628497
},
"id":6077243,
"name":"Montreal",
"cod":200
}
And I would like to display just the temp field.
If you have any idea guys it's welcomed!
Thanks a lot.
You could leverage the Elvis operator since your data are loaded asynchronously:
<span class="meteo">{{meteo?.main.temp | json}}°C</span>
Try setting the data on this.meteo.data
getMeteo() {
this._meteoService.getMeteo()
.subscribe(
data => this.meteo.data = data,
error => this.errorMessage = <any>error);
}
and then displaying it with
<span class="meteo">{{meteo.data.main.temp}}°C</span>

Resources