Changed request does not work in angular 6 - angular6

I have following function which calls the refresh service to get new token for authorization:
private handle401Error(request: HttpRequest<any>, next: HttpHandler) {
if(!this.isRefreshingToken) {
this.isRefreshingToken = true;
return this.authService.refreshToken()
.subscribe((response)=> {
if(response) {
const httpsReq = request.clone({
url: request.url.replace(null, this.generalService.getUserId())
});
return next.handle(this.addTokenToRequest(httpsReq, response.accessToken));
}
return <any>this.authService.logout();
}, err => {
return <any>this.authService.logout();
}, () => {
this.isRefreshingToken = false;
})
} else {
this.isRefreshingToken = false;
return this.authService.currentRefreshToken
.filter(token => token != null)
.take(1)
.map(token => {
return next.handle(this.addTokenToRequest(request, token));
})
}
}
When the response is not undefined and request is returned back it does not call the new request

Ok the thing was that the bearer was quoted like below:
But I have still one issue the request does not invoke the new request, when I refresh the page it gives data with new token, instead like I previously had unauthorized error.

Related

Vue JS, Axios retry request. Prevent JSON quotes

I have an axios interceptor for cases, where I need the user to be authorized, but he isn't. For example, because the token is expired.
Now, after a token refresh, the original request should be retried.
However, currently the original requests, seems to be changed, so that the Server gives me a JSON.parse error.
SyntaxError: Unexpected token " in JSON at position 0
at JSON.parse (<anonymous>)
at createStrictSyntaxError (/var/app/current/node_modules/body-parser/lib/types/json.js:158:10)
at parse (/var/app/current/node_modules/body-parser/lib/types/json.js:83:15)
at /var/app/current/node_modules/body-parser/lib/read.js:121:18
at invokeCallback (/var/app/current/node_modules/raw-body/index.js:224:16)
at done (/var/app/current/node_modules/raw-body/index.js:213:7)
at IncomingMessage.onEnd (/var/app/current/node_modules/raw-body/index.js:273:7)
at IncomingMessage.emit (events.js:314:20)
at IncomingMessage.EventEmitter.emit (domain.js:483:12)
at endReadableNT (_stream_readable.js:1241:12)
This is because, instead of the original request, that is JSON, it seems to process it again, puts it in quotes etc., so it becomes a string and the bodyparser, throws the error above.
So the request content, becomes:
"{\"traderaccount\":\"{\\\"traderaccountID\\\":\\\"undefined\\\",\\\"traderID\\\":\\\"2\\\",\\\"name\\\":\\\"Conscientious\\\",\\\"order\\\":99,\\\"myFxLink\\\":\\\"\\\",\\\"myFxWidget\\\":\\\"\\\",\\\"copyFxLink\\\":\\\"83809\\\",\\\"tokenLink\\\":\\\"\\\",\\\"tradertext\\\":{\\\"tradertextID\\\":\\\"\\\",\\\"traderaccountID\\\":\\\"\\\",\\\"language\\\":\\\"\\\",\\\"commission\\\":\\\"\\\",\\\"affiliateSystem\\\":\\\"\\\",\\\"leverage\\\":\\\"\\\",\\\"mode\\\":\\\"\\\",\\\"description\\\":\\\"\\\"},\\\"accountType\\\":\\\"\\\",\\\"accountTypeID\\\":1,\\\"minInvest\\\":2000,\\\"currency\\\":\\\"\\\",\\\"currencySymbol\\\":\\\"\\\",\\\"currencyID\\\":1,\\\"affiliateSystem\\\":1}\"}"
instead of
{"traderaccount":"{\"traderaccountID\":\"undefined\",\"traderID\":\"2\",\"name\":\"Conscientious\",\"order\":99,\"myFxLink\":\"\",\"myFxWidget\":\"\",\"copyFxLink\":\"83809\",\"tokenLink\":\"\",\"tradertext\":{\"tradertextID\":\"\",\"traderaccountID\":\"\",\"language\":\"\",\"commission\":\"\",\"affiliateSystem\":\"\",\"leverage\":\"\",\"mode\":\"\",\"description\":\"\"},\"accountType\":\"\",\"accountTypeID\":1,\"minInvest\":2000,\"currency\":\"\",\"currencySymbol\":\"\",\"currencyID\":1,\"affiliateSystem\":1}"}
from the original axios request content.
Both are the unformated request contents, that I can see in the developer network console.
The content type, is application/json in both cases.
Below is the Interceptor code:
Axios.interceptors.response.use(
(response) => {
return response;
},
(err) => {
const error = err.response;
if (
error !== undefined &&
error.status === 401 &&
error.config &&
!error.config.__isRetryRequest
) {
if (this.$store.state.refreshToken === "") {
return Promise.reject(error);
}
return this.getAuthToken().then(() => {
const request = error.config;
request.headers.Authorization =
Axios.defaults.headers.common[globals.AXIOSAuthorization];
request.__isRetryRequest = true;
return Axios.request(request);
});
}
return Promise.reject(error);
}
);
private getAuthToken() {
if (!this.currentRequest) {
this.currentRequest = this.$store.dispatch("refreshToken");
this.currentRequest.then(
this.resetAuthTokenRequest,
this.resetAuthTokenRequest
);
}
return this.currentRequest;
}
private resetAuthTokenRequest() {
this.currentRequest = null;
}
// store refreshToken
async refreshToken({ commit }) {
const userID = this.state.userID;
const refreshToken = Vue.prototype.$cookies.get("refreshToken");
this.commit("refreshLicense");
commit("authRequest");
try {
const resp = await axios.post(serverURL + "/refreshToken", {
userID,
refreshToken,
});
if (resp.status === 200) {
return;
} else if (resp.status === 201) {
const token = resp.data.newToken;
const newRefreshToken = resp.data.newRefreshToken;
Vue.$cookies.set(
"token",
token,
"14d",
undefined,
undefined,
process.env.NODE_ENV === "production",
"Strict"
);
Vue.$cookies.set(
"refreshToken",
newRefreshToken,
"30d",
undefined,
undefined,
process.env.NODE_ENV === "production",
"Strict"
);
axios.defaults.headers.common[globals.AXIOSAuthorization] = token;
commit("authSuccessRefresh", { newRefreshToken });
} else {
this.dispatch("logout");
router.push({
name: "login",
});
}
} catch (e) {
commit("authError");
this.dispatch("logout");
}
So, can you help me to prevent Axios on the retried request to change the request content. So it doesn't put it into quotes and quote the already exisitng quotes?
Thanks to the comment I found a solution.
Try to parse the content before resending it:
axios.interceptors.response.use(
(response) => response,
(error) => {
const status = error.response ? error.response.status : null;
if (status === 401 && error.config && !error.config.__isRetryRequest) {
return refreshToken(useStore()).then(() => {
const request = error.config;
request.headers.Authorization =
axios.defaults.headers.common["Authorization"];
request.__isRetryRequest = true;
try {
const o = JSON.parse(request.data);
if (o && typeof o === "object") {
request.data = o;
}
} catch (e) {
return axios.request(request);
}
return axios.request(request);
});
}
return Promise.reject(error);
});

Execute query before sending message

I'm making a Messenger bot in NodeJS. I want users be able to request all their trains. The problem is that we want to execute a query before NodeJS sends a message to the user.
I searched for asynchronous functions
function handlePostback(sender_psid, received_postback) {
let response;
// Get the payload for the postback
let payload = received_postback.payload;
// Set the response based on the postback payload
switch(payload){
case "yes" :
let data = null
axios.get('http://api.irail.be/connections/?from=Mechelen&to=Puurs&date=010219&time=1650&timesel=departure&format=json&lang=en&fast=false&typeOfTransport=trains&alerts=false&resul1=1')
.then(function (response) {
// handle success
data = data.response;
})
response = {
"text": data.connections.arrival.name
}
break;
}
callSendAPI(sender_psid, response);
}
function callSendAPI(sender_psid, response) {
// Construct the message body
let request_body = {
"recipient": {
"id": sender_psid
},
"message": response
}
// Send the HTTP request to the Messenger Platform
request({
"uri": "https://graph.facebook.com/v2.6/me/messages",
"qs": { "access_token": PAGE_ACCESS_TOKEN },
"method": "POST",
"json": request_body
}, (err, res, body) => {
if (!err) {
console.log('message sent!')
} else {
console.error("Unable to send message:" + err);
}
});
}
So as you can see, the script will already sending the message to the user on Messenger before the query is executed.
There are some unneccessary variables and problems in your code (data = data.response should probably be data = response.data, for example), this would be a modern version with async/await and arrow functions. You do not need a callback function in that case, callSendAPI will be called after the AJAX request. I have also removed the switch, because a simple if is sufficient:
const handlePostback = async (sender_psid, received_postback) => {
// Get the payload for the postback
const payload = received_postback.payload;
// Set the response based on the postback payload
if (payload === 'yes') {
try {
const response = await axios.get('http://api.irail.be/connections/?from=Mechelen&to=Puurs&date=010219&time=1650&timesel=departure&format=json&lang=en&fast=false&typeOfTransport=trains&alerts=false&resul1=1');
callSendAPI(sender_psid, {
'text': response.data.connections.arrival.name
});
} catch (err) {
console.log(err);
}
}
};
Side note: I would not use 2 different ways to do http requests, assuming you are using superagent too? Because http.request would be a possibility with Node.js, but request looks like superagent ;)
Put callSendAPI() in your Axios callback
function handlePostback(sender_psid, received_postback) {
let response;
// Get the payload for the postback
let payload = received_postback.payload;
// Set the response based on the postback payload
switch (payload) {
case "yes":
let data = null
axios.get('http://api.irail.be/connections/?from=Mechelen&to=Puurs&date=010219&time=1650&timesel=departure&format=json&lang=en&fast=false&typeOfTransport=trains&alerts=false&resul1=1')
.then(function(response) {
// handle success
data = data.response;
})
response = {
"text": data.connections.arrival.name
}
callSendAPI(sender_psid, response);
break;
}
}

Angular 4 wait till http.get execute to continue

I'm creating a new register form an app with Ionic and using ASP.Net(C#) as my API.
I want to check if user exists when the input blur event is activate.
The problem is that my code isn't waiting till the server returns a value to continue.
What am I doing wrong? Is there a way to do that?
THIS IS MY API CODE:
[HttpGet]
public JsonResult verifyEmail(string email)
{
var result = Domain.Repository.UserController.Find(email:email);
if (result != null)
{
return Json(new { erro = true, message = "Email already registered!" }, JsonRequestBehavior.AllowGet);
}
else
{
return Json(new { erro=false,message = "Email is valid!" },JsonRequestBehavior.AllowGet);
}
}
I CREATED A PROVIDER TO MAKE THE HTTP REQUEST(authProvider):
getData(data,func)
{
return new Promise( (resolve,reject)=>{
this.http.get(apiUrl+func, {params:data})
.subscribe(
res=>{
resolve(res.json());
},
async (err)=>{
reject(err);
});
});
}
AND HERE IS MY register.ts code:
validate()
{
let validEmail;
validEmail= this.checkEmail();// I WANT THAT the "validEmail" receives returned value before continue.
return true;
}
AND THE LAST THING IS MY FUNCTION THAT WILL CALL THE PROVIDER:
checkEmail()
{
return this.authService.getData({email:this.model.email},"Account/verifyEmail").then((result)=>{
let response = <any>{};
response=result;
if(response.erro)
{
return response.message
}else
{
return true
}
},(err)=>{
this.toastService.presentToast("ERROR:"+err,"bottom",undefined,"toast-error");
});
}
Thanks in advance..
getData(data,func)
{
this.http.get(apiUrl+func, {params:data})
.map(res => {
return res.json();
})
.toPromise();
}
or with async/await
async getData(data,func)
{
let result = await this.http.get(apiUrl+func, {params:data})
.toPromise();
return result.json();
}
Now for the validate function:
async validate()
{
let validEmail;
await this.checkEmail();
return true;
}
Point is you cant jump from a sync function to an async or vice versa.
Validate needs to return a promise/observable because it is executes asynchronous functions.

Convert Promise object to JSON in Angular 2

I'm trying to make an HTTP POST and then check the response to see if it fails or succeeds.
The HTTP call looks like this :
doLogin(credentials) {
var header = new Headers();
header.append('Content-Type', 'application/x-www-form-urlencoded');
var body = 'username=' + credentials.username + '&password=' + credentials.password;
return new Promise((resolve, reject) => {
this.http.post(this.url, body, {
headers: header
})
.subscribe(
data => {
resolve(data.json());
},
error => {
resolve(error.json());
}
);
});
}
And the call of this function is the following :
data: Object;
errorMessage: Object;
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).then(
result => {
this.data = result;
console.log(this.data);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
On Chrome console, the data is the following :
Object {status: "Login success", token: "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJjcmlzdGkiLCJ1c2VyS…blf1AzZ6KzRWQFNGXCrIeUHRG3Wrk7ZfCou135WmbVa15iYTA"}
How can I access the status in Angular 2? Because if I'm trying to access this.data.status, it's not working.
Should I create a class with the status and token properties?
To answer your question, you can use the response.okboolean that's available in the subscription of the observable from the http.
So based on your code you could pass the data object straight to the promise and inspect data.ok before parsing the data.json.
//...
return new Promise((resolve, reject) => {
this.http.post(this.url, body, {
headers: header
})
.subscribe(resolve,
error => {
reject(error.json());
}
);
});
// then you would have something like this:
this._loginService.doLogin(this.credentials).then(
result => {
if (result.ok) {
this.data = result;
console.log(this.data);
}
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
})
SUGGESTION
Now, I would recommend getting rid of the promise, as I believe you don't really need it. whoever is consuming your service can just subscribe to the observable returned by the http post, like so:
doLogin(credentials) {
let header = new Headers();
header.append('Content-Type', 'application/x-www-form-urlencoded');
var body = 'username='+credentials.username+'&password='+credentials.password;
return this.http.post(this.url, body, { headers: header });
}
Then, when logging in:
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).subscribe(response => {
if (response.ok) { // <== CHECK Response status
this.data = response.json();
console.log(this.data);
} else {
// handle bad request
}
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
Hope this helps!
You could do it like this:
data: Object;
errorMessage: Object;
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).then(
(result: any) => {
this.data = result;
console.log(this.data);
console.log(this.data.status);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
Set the result to type any. That way you'll be able to access the status, however you could create a class and use rxjs/map within your service to populate the class if you so desire.

Angular 2:Not able to get a token in another component which is stored in local storege

I have one application which include login and home component,
login.service.ts
let body = JSON.stringify(data);
console.log("logged in user",body);
return this._http.post('http://localhost:8080/api/user/authenticate', body, { headers: contentHeaders })
.map(res => res.json())
.map((res) => {
var token1:any = res;
console.log(token1);
if (token1.success) {
localStorage.setItem('auth_token', token1.token);
this.LoggedIn = true;
}
return res.success;
});
}
isLoggedIn() {
return this.LoggedIn;
}
in this service i am getting token in variable token1 and isLogged method contain
constructor(private _http: Http) {
this.LoggedIn = !!localStorage.getItem('auth_token'); }
Login.component.ts
login(event, username, password)
{
this.loginService.login(username, password)
.subscribe(
response => {
this.router.navigate(['/home']);
alert("login successfull");
},
error => {
alert(error.text());
console.log(error.text());
}
);
From this login i can able to authenticate and and its routing to home component,
Home.serice.ts
getClientList()
{
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let authToken = localStorage.getItem('auth_token');
headers.append('X-auth-Token', 'authToken')
return this._http.get('http://localhost:8080/api/v1/client/list?isClient=Y', {headers})
.map(res => res.json())
}
Home.component.ts
onTestGet()
{
this._httpService.getClientList()
.subscribe(
data => this.getData = JSON.stringify(data),
error => alert(error),
() => console.log("finished")
);
}
now question is how can i access that token in home component which is in token1 varible(login) i have tired to getitem token.but i am getting token null.please anybody help me.
thanks in advance
localStorage.getItem('auth_token')
This should work, but you are getting null, because lifecycle of the data different.
I suggest you to use Subject construction for this purpose, especially you already have service with data.
Example:
loginInfo$ = new Subject();
private _logininfo = null;
getLoginData () {
if(!_logininfo) {
this.http..... { this._loginInfo = data;
this.loginInfo$.next(data); }
return this.loginInfo$.first()
}
else return Observable.of(this._logininfo);
}
So now, your service at the same time storage of data and handler for missing login.