I have url, this url needs authentication with username and password. On PHP I made it with curl_setopt(CURLOPT_USERPWD, $username . ':' . $password), I can't find any solution how to set password and username on same link on NestJS.
import { Injectable, Scope, HttpService } from '#nestjs/common';
import { ImporterService } from '../importer.service';
import { map } from 'rxjs/operators';
#Injectable({ scope: Scope.REQUEST })
export class Supplier extends ImporterService {
supplierName = 'supplierName';
fileDownload: boolean = false;
username = 'username;
password = 'password';
async parse() {
await this.checkSupplierExist(this.supplierName);
return this.httpService
.get(
'https://www.link.com/restful/export/api/products.xml?acceptedlocales=en_US&addtags=true',
)
.pipe( map(response => console.log(response)));
}
}
this response sends 401, cause it needs authentication. I cannot figure out how to set username or password. Can anyone help?
From me I have a Config service which handles http calls, looks like this:
#Injectable()
export class ConfigService {
private readonly envConfig: { [key: string]: string };
private servers: Object = {};
constructor(private httpService: HttpService) {
this.envConfig = {
PORT: process.env.PORT,
MONGODB_URI: process.env.MONGODB_URI,
MONGODB_SESSION_URI: process.env.MONGODB_SESSION_URI,
SESSION_SECRET: process.env.SESSION_SECRET
};
const externals = JSON.parse(process.env.EXTERNALS);
for (const lang in externals) {
this.servers[lang] = externals[lang];
}
}
get(key: string): string {
return this.envConfig[key];
}
getServer(lang: string, method: string, url: string, headers: Object, params?: Object, data?: Object) {
const config = { baseURL: this.servers[lang], url, headers, method, data, params };
return this.httpService.request(config).toPromise();
}
}
As you can see in the getServer method, you can add headers as well.
I hope this is what you're looking for
Related
I am using NestJS and its JWT package based on jsonwebtoken. The generated token is always being invalid, and I am getting a 500 - Internal Server Error.
What might be the problem?
My login function in the AuthService:
async login(email: string, password: string, isAdmin?: boolean, isVIP?: boolean){
let user = await this.usersService.findByEmail(email);
if(!user){
throw new NotFoundException('No user with this email could be found.');
}
const isEqual = await bcrypt.compare(password, user.password);
if(!isEqual){
throw new BadRequestException('Email and password do not match');
}
const secret = 'secretkey';
const payload = {email: user.email, userId: user._id.toString()}
const token = this.jwtService.sign(payload, {secret, expiresIn: '1h'});
return [email, isAdmin, isVIP, token];
}
My verification logic in the AuthGuard
`
import { BadRequestException, CanActivate, ExecutionContext, Inject } from "#nestjs/common";
import { JwtService } from "#nestjs/jwt/dist";
import { JwtConfigService } from "src/config/jwtconfig.service";
export class JwtAuthGuard implements CanActivate {
constructor(#Inject(JwtService) private jwtService: JwtService){}
canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
const authHeader = request.get('Authorization');
if (!authHeader) {
throw new BadRequestException('Not authorized');
}
const token = authHeader.split(' ')[1];
let decodedToken;
try {
decodedToken = this.jwtService.verify(token, {secret: 'secretkey'});
} catch (err) {
throw new Error('Cannot verify token.')
}
if(!decodedToken){
throw new BadRequestException('Not authenticated')
}
request.userId = decodedToken.userId;
console.log({decodedToken, token});
return request.userId;
};
}
My current JWT setup in the UsersModule imports (I have no AuthModule); I tried all the other configurations in the official docs, too.
JwtModule.register({
secret: 'secretkey',
publicKey: '...',
privateKey: '...',
secretOrKeyProvider: (
requestType: JwtSecretRequestType,
tokenOrPayload: string | Object | Buffer,
verifyOrSignOrOptions?: jwt.VerifyOptions | jwt.SignOptions
) => {
switch (requestType) {
case JwtSecretRequestType.SIGN:
return 'privateKey';
case JwtSecretRequestType.VERIFY:
return 'publicKey';
default:
return 'secretkey';
}
},
})
`
My jwtconfig.ts, which I don't think is being used:
`
import { JwtOptionsFactory, JwtModuleOptions } from '#nestjs/jwt'
export class JwtConfigService implements JwtOptionsFactory {
createJwtOptions(): JwtModuleOptions {
return {
secret: 'secretkey'
};
}
}
`
I solved the problem by switching my guard to a middleware.
I am new to nestjs and also to asking questions on stack overflow.
And although i am able to perfectly perform get requests i have trouble sending a post request using form data.
And although i am able to successfully send a post request using form-urlencoded and raw json i am having trouble dealing with form data.
While trying to send a post request to my db I seem to get an error which says: ER_NO_DEFAULT_FOR_FIELD: Field 'username' doesn't have a default value
even though I provide a value for it in postman.
Below is the code for my repo:
import { EntityRepository, Repository } from 'typeorm';
import { User } from './user.entity';
import { CreateUserDTO } from './dto/create-user.dto';
#EntityRepository(User)
export class UserRepository extends Repository<User> {
getUser() {
const query = this.createQueryBuilder('user');
return query.getMany();
}
createUser(createUserDTO: CreateUserDTO) {
const {username, email } = createUserDTO;
// tslint:disable-next-line:no-console
console.log('Repo', username);
// tslint:disable-next-line:new-parens
const newuser = new User(); //edited after Natan's comment
newuser.username = username;
newuser.email = email;
return newuser.save();
}
}
This is my entity code:
#Entity()
export class User extends BaseEntity {
#PrimaryGeneratedColumn()
id: number;
#Column()
username: string;
#Column()
email: string;
}
and my post request in the controller:
#Post()
createUser(
#Body() createUserDTO: CreateUserDTO,
) {
// tslint:disable-next-line:no-console
console.log('creating new user', createUserDTO);
return this.userService.createUser(createUserDTO);
}
And here is a picture of the post request in postman:
You must use () to instantiate a class in TS, like:
createUser(createUserDTO: CreateUserDTO) {
const {username, email } = createUserDTO;
// tslint:disable-next-line:no-console
console.log('Repo', username);
// tslint:disable-next-line:new-parens
const newuser = new User(); // <- HERE IS new User()
newuser.username = username;
newuser.email = email;
return newuser.save();
}
I'm currently rewriting old request service to use HttpClient instead of Http. My app makes use of ngrx store and after I rewrote request service, it stopped working.
here's my request service:
import { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import { ToastController } from 'ionic-angular';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { Config } from '../app/app.config';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { Version } from '#angular/compiler';
export enum HttpStatus {
UNAUTHORIZED,
WRONGVERSION,
UNVERIFIED,
NONETWORK,
}
export interface HttpNotifierData {
status: HttpStatus
}
#Injectable()
export class HttpClientService {
private httpNotifier: ReplaySubject<HttpNotifierData>;
constructor(
public toastCtrl: ToastController,
private _http: HttpClient,
) {
this.httpNotifier = new ReplaySubject();
}
createHeaders(contentType?: string) {
var headers = new HttpHeaders();
let token = localStorage.getItem('auth_token');
let expires = localStorage.getItem('auth_expires');
let appVersion = Config.version+'';
if(token)
headers = headers.set( 'Authorization', 'Bearer ' + token);
if(expires)
headers = headers.set( 'TokenExpiration', expires);
if(appVersion)
headers = headers.set( 'App-Version', appVersion);
if(contentType === 'form')
headers = headers.set('Content-Type','application/x-www-form-urlencoded');
return headers;
}
createAppVersionHeader(headers: Headers) {
let appVersion = Config.version+'';
headers.append('App-Version', appVersion);
}
getHttpNotifier(): ReplaySubject<HttpNotifierData> {
return this.httpNotifier;
}
request(verb: string, url: string, data?: any, contentType?: string) {
let headers = this.createHeaders(contentType);
return this._http.request(verb, url, {
body: data,
headers: headers
}).catch(err => {
if (err.status == 0) {
this.httpNotifier.next({status: HttpStatus.NONETWORK});
err._body = 'Kunne ikke kontakte baksystem';
} else if (err.status == 401) {
this.httpNotifier.next({status: HttpStatus.UNAUTHORIZED});
} else if (err.status == 403) {
this.httpNotifier.next({status: HttpStatus.UNVERIFIED});
} else if (err.status == 412) {
this.httpNotifier.next({status: HttpStatus.WRONGVERSION});
} else {
// TODO: Convert API error to user friendly error
this.toastCtrl.create({
message: err._body,
duration: 3000,
showCloseButton: true,
closeButtonText: "Lukk",
cssClass: 'error',
}).present();
}
throw err;
});
}
get(url) {
let cache = '?cache=' + Math.ceil(Math.random() * 100000);
return this.request('GET', url + cache);
}
post(url, data, contentType = 'json') {
return this.request('POST', url, data, contentType);
}
put(url, data) {
return this.request('PUT', url, data);
}
delete(url) {
return this.request('DELETE', url);
}
}
my user auth service:
import { Injectable } from '#angular/core';
import { Config } from '../app/app.config';
import { HttpClientService } from "./http.service";
#Injectable()
export class UserService {
constructor(
private _http: HttpClientService
) { }
login(username: string, password: string) {
var data = "grant_type=password&username=" + username + "&password=" + password + "&deviceId=test";
return this._http.post(Config.apiUrl + 'Token', data, 'form');
}
getPin(phone: string) {
return this._http.post(Config.apiUrl + 'api/account/forgotPassword', {phoneNumber: phone})
}
}
my ngrx effect for authenticating user:
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/observable/of';
import { Injectable } from '#angular/core';
import { Effect, Actions } from '#ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { UserService } from '../services/user.service';
import * as UserActions from '../actions/user.actions';
#Injectable()
export class UserEffects {
constructor(
private actions: Actions,
private userService: UserService
) {}
#Effect()
login:Observable<any> = this.actions
.ofType(UserActions.LOGIN)
.map((action: UserActions.Login) => action.payload)
.switchMap(payload => {
return this.userService.login(payload.username, payload.password)
.map((response:any) => new UserActions.LoginSuccess(JSON.parse(response._body)))
.catch((error) => Observable.of(new UserActions.LoginFailed(error._body)))
});
#Effect()
getPin:Observable<any> = this.actions
.ofType(UserActions.GET_PIN)
.map((action: UserActions.GetPin) => action.payload)
.switchMap(payload => {
return this.userService.getPin(payload)
.map((response: any) => new UserActions.GetPinSuccess())
.catch((error) => Observable.of(new UserActions.GetPinFailed(error._body)))
});
}
when debugging, I have this error appearing in effect module:
however, in network section I can see that request is completed successfully:
what can be wrong with my service?
ok, so I figured out the solution.
effects for login should have pipe and no json parsing:
#Effect()
login:Observable<any> = this.actions
.ofType(UserActions.LOGIN)
.map((action: UserActions.Login) => action.payload)
.switchMap(payload => {
return this.userService.login(payload.username, payload.password).pipe()
.map((response:any) => new UserActions.LoginSuccess(response))
.catch((error) => Observable.of(new UserActions.LoginFailed(error._body)))
});
how I can write headers using way nest.js?
I'm currently using this:
import { Controller, Body, Get, Post, HttpCode, HttpStatus, Req, Res } from '#nestjs/common';
import { Request, Response } from 'express';
import { AuthService } from './auth.service';
import { Usuario } from '../usuario/usuario.entity';
import { JsonWebTokenError } from 'jsonwebtoken';
import { request } from 'http';
#Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) { }
#Post('login')
#HttpCode(HttpStatus.OK)
async login(#Body('username') username: string, #Body('password') password: string, #Res() response: Response) {
this.authService
.validateUser(username, password)
.then((token) => {
response.setHeader('Authorization', 'Bearer ' + token);
let respuesta: any = {};
respuesta.success = true;
respuesta.token = token;
return response.send(respuesta);
});
}
}
I do not want to use response.setHeader('Authorization', 'Bearer ' + token); and return response.send(respuesta);
Thanks for your answers!
NestJS is build on top of express, so do it like in express:
async login(#Body('username') username: string, #Body('password') password: string, #Res() res: Response) {
const token = await this.authService.validateUser(username, password);
res.set('Authorization', 'Bearer ' + token);
res.send({
success: true,
token,
})
});
In latest versions you could use the #Header decorator within NestJS Core.
import { Controller, Get, Req, Header, Res } from '#nestjs/common';
import { Request, Response } from 'express';
#Controller('cookies')
export class CookiesController {
#Get('set')
// #Header('Set-Cookie', 'cookieName = 12345') // "Usin header decorator"
setCookie(#Res() response: Response): Response {
/*
* If using express approach, pass #Res as param decorator
*/
response.cookie('rememberme', '1') // Using express res object.
return response.send('Cookie has been set! :)')
}
#Get()
checkCookie(#Req() request: Request ): string {
console.log(Object.keys(request.cookies))
if(Object.keys(request.cookies).length > 0){
console.log('cookies =>', request.cookies)
return 'Cookies are set :)'
} else {
return 'Uh, oh! Cookie hasn\'t been set :\'('
}
}
}
Trying to make Login feature using angular-2 where I have used one login component, authservice, logingard with canActive.
While following example from angular2 document, I don't get value of loggedin in guard file and it asks every time for login
Posting sample code here
AuthService
export class AuthService {
loggedIn: boolean = false;
isLoggedIn() {
return this.loggedIn;
}
login(credentials) {
let user = JSON.stringify(credentials);
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this._http.post(this._apiUrl, user, options)
.map(res => res.json())
.map((res) => {
this.loggedIn = true;
}
return res;
});
}}
Loggedin Guard
export class LoggedInGuard implements CanActivate {
constructor(private _auth: AuthService, private _router: Router) {}
canActivate() {
//Get problem here. Everytime this comes false
if(this._auth.isLoggedIn()) { return true; }
this._router.navigate(['login']);
}
}
login component
export class LoginComponent {
constructor(private userService: AuthService, private router: Router) {}
onSubmit(email, password) {
this.userService.login(email, password).subscribe((result) => {
if (result) {
this.router.navigate(['']);
}
});
}
}
Btw, following example of
https://medium.com/#blacksonic86/angular-2-authentication-revisited-611bf7373bf9#.723a4ssji
without localstorage