Hi I am trying to authenticate users and once the server gives user's information, I want to use the information of the user.
But for some reasons, even though I did the log in process without any error and I can see from developer's tool that the POST request has been successful, I can't quite set currentUser in my localStorage (giving me null if I console.log it)
What am I doing wrong?
This is my authentication service.
export class AuthenticationService {
constructor(private http: Http, private router: Router) { }
login(email: string, password: string): Observable<User>{
const headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' });
headers.append('Access-Control-Allow-Headers', 'Content-Type');
headers.append('Access-Control-Allow-Methods', 'post');
headers.append('Access-Control-Allow-Origin', '*');
headers.append("X-Requested-With", "XMLHttpRequest");
let options = new RequestOptions({ headers: headers });
let body = new URLSearchParams();
body.set('email', email);
body.set('password', password);
return this.http.post(`${environment.baseurl}` + '/api/v2/member/login', body, options)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let user = res.json();
if (user && user.token) {
localStorage.setItem('currentUser', JSON.stringify(user));
}
return user.data || {};
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
}
private handleError(error: any) {
if (error.status === 401) {
return Observable.throw(error.status);
} else {
return Observable.throw(error.status || 'Server error');
}
}
}
And this is my log-in component
export class LoginPageComponent implements OnInit {
constructor(private location: Location,
private route: ActivatedRoute,
private router: Router,
private authenticationService: AuthenticationService,
private alertService: AlertService) {
}
model: any = {};
loading = false;
returnUrl: string;
error = '';
ngOnInit() {
// get return url from route parameters or default to '/'
this.returnUrl = this.route.snapshot.queryParams['main'] || '/';
}
currentUser: User;
login() {
this.loading = true;
this.authenticationService.login(this.model.email, this.model.password)
.subscribe(
data => {
this.currentUser = data;
this.router.navigate([this.returnUrl]);
},
error => {
this.error = "Wrong ID or PW";
this.loading = false;
});
}
backClicked() {
this.location.back();
}
}
And this is my home component
export class MainComponent {
onClick() {
this.auth.logout() //if user clicks logout button
}
currentUser: User;
users: User[] = [];
items: Object[] = [];
constructor(private authguard: AuthGuard, private auth:AuthenticationService) {
this.currentUser = JSON.parse(localStorage.getItem('currentUser'));
console.log(localStorage.getItem('currentUser')); //Printing null
}
}
And the model for user information is this.
export interface User {
birthday: number;
email:string;
genderType:string;
memberType: string;
name: string;
phone: string;
}
What im receiving
Why is it printing null?
Thank you!
Mistakes you made
passing email and password as URLSearchParams.
You are adding all the headers to your login method which is not necessary
The service should contain method as below
login(body: any, options?: RequestOptionsArgs): Observable<Response> {
return this.http.post('loginUrl', body);
}
Component should contain the below code
login() {
let user ={
email : this.model.email
password : this.model.password)
}
this.loading = true;
this.authenticationService.login(user)
.subscribe(data => {
this.authenticationService.extractData(data);///call to store token in the localstorage
this.router.navigate([this.returnUrl]);
},
error => {
this.error = "Wrong ID or PW";
this.loading = false;
});
}
Related
I'm trying to setup a Vue2js app with node.js/express, using JWT authentication.
When signing in token is generated (with bearer) and stored in the client-side (Vuex) successfully.
When reload token somehow dissapers from header and I don't know why?
So when calling fetchAccountFromToken function from helpers/token.js I have below error on the server side:
"TypeError: Cannot read property 'split' of undefined"
helpers/token.js
export function fetchAccountFromToken(token) {
return JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString('utf-8'))['user']
}
And I have this code in server.js
app.post('/login', async (req, res) => {
if (req.body == null) {
res.status(401).json({ error: 'Invalid login. Please try again' })
} else {
const userService = new UserService()
const token = await userService.loginUser({
email: req.body.email,
password: req.body.password
})
console.log(token)
if (token) {
res.json({ token })
} else {
res.status(401).json({ error: 'Invalid login. Please try again' })
}
}
})
UserService.js
export default class UserService {
async loginUser(loginUserRequest) {
const { email, password } = loginUserRequest
const userRepository = new UserRepository()
const userDto = await userRepository.getUserByEmail(email)
if (userDto.email === email && userDto.password === password) {
let user = {
id: userDto.id,
email: userDto.email,
firstName: userDto.firstName,
lastName: userDto.lastName,
role: userDto.role
}
return jwt.sign({ user }, 'the_secret_key') //secret key je za validacijo tokena
}
return null
// return res.status(401).json({ error: 'Invalid login. Please try again.'}) // NEEDS to send error if credentials don't match !!!! //
}
UserRepository.js
export default class UserRepository {
async getUserByEmail(email) {
let dbContext = new DbContext()
try {
const query = 'SELECT id, email, password, firstName, lastName, role FROM accounts WHERE email = ?'
const users = await dbContext.query(query, [email])
return users[0]
} finally {
dbContext.close()
}
}
And I have this code in the VueX store module user.js:
export const state = {
user: null
}
export const mutations = {
SET_USER_DATA(state, data) {
console.log('logging in with data data:', data)
let { token } = data
localStorage.setItem('token', token)
let tokenPayloadJson = atob(token.split('.')[1])
let tokenPayload = JSON.parse(tokenPayloadJson)
let user = tokenPayload.user
state.user = user
localStorage.setItem('user', JSON.stringify(user))
console.log('called set user data')
axios.defaults.headers.common['Authorization'] = `Bearer ${data.token}`
},
CLEAR_USER_DATA() {
localStorage.removeItem('token')
localStorage.removeItem('user')
location.reload()
}
}
export const actions = {
login({ commit }, credentials) {
return axios
.post('//localhost:3000/login', credentials)
.then(({ data }) => {
commit('SET_USER_DATA', data)
})
},
fetchUser(id) {
return AccountService.getUser(id)
.then(response => {
return response.data
})
},
logout({ commit }) {
commit('CLEAR_USER_DATA')
}
}
export const getters = {
loggedIn(state) {
return !!state.user
}
}
I don't see storing the token to VueX, just saving it to localStorage. Additionally I don't see how you are reading it from it (neither localStorage nor VueX store). You can load it from localStorage when initializing the store like this:
export const state = {
user: localStorage.getItem('user'),
token: localStorage.getItem('token')
}
I am trying to create a login form for my website. I'm using agular , express and mongoDB
Here's my controller of login function:
loginUser: (req, res) => {
User.findOne({
username: req.body.login_username
})
.then(user => {
bcrypt.compare(req.body.login_password, user.password)
.then(result => {
if (result) {
req.body.login_username = user.username
res.json({
message: "Success!",
added: true
});
} else {
console.log('Failed login attempt')
res.json({
message: "Error!",
error: err
});
}
}).catch(console.error, console.log(req.body.login_password, user.password))
})
}
and here is my login components:
userID: string;
userData: any;
loginUser: any;
error = "";
constructor(
private router: Router,
private route: ActivatedRoute,
private httpService: HttpService
) {}
ngOnInit() {
this.userID = this.route.snapshot.paramMap.get("id");
this.getSingleUser();
this.loginUser = { username: "", password: "" };
}
getSingleUser() {
let observable = this.httpService.getOneUser(this.userID);
observable.subscribe((data) => {
this.userData = data;
});
}
onSubmit() {
let observable = this.httpService.loginUser(this.loginUser);
observable.subscribe((data: any) => {
console.log("Wrong");
if (data.error) {
this.error = data.error.errors.name.message;
} else {
this.getSingleUser();
this.router.navigate([""]);
}
});
}
When I click on button my terminal getting an error like this:
undefined $2b$20$8DmOjsDm3h5q/jEq9lNauezUdFYdL6EBt9gjmCu8/0DU0kAnSSIA2
Error: data and hash arguments required
at Object.compare (/Users/nhannguyen/Desktop/personal_project/instagram/node_modules/bcrypt/bcrypt.js:208:17)
at /Users/nhannguyen/Desktop/personal_project/instagram/node_modules/bcrypt/promises.js:29:12
at new Promise ()
at Object.module.exports.promise (/Users/nhannguyen/Desktop/personal_project/instagram/node_modules/bcrypt/promises.js:20:12)
at Object.compare (/Users/nhannguyen/Desktop/personal_project/instagram/node_modules/bcrypt/bcrypt.js:204:25)
at /Users/nhannguyen/Desktop/personal_project/instagram/server/controllers/users.js:65:24
at processTicksAndRejections (internal/process/task_queues.js:97:5)
Please add .catch(console.error) after the .then() to catch the full error.
After that check if the values are really there and if not, check if the body-parser plugin is installed
Please assist with angular guards, I have the following angular Guard below :
export class RoleGuard implements CanActivate {
private role: any;
constructor(private router: Router, private accountService: AccountService)
{}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
this.accountService.getUserRole().subscribe(res => this.role = res);
if (this.role === 'admin') {
return true;
}
return false;
}
}
in the service:
getUserRole(): Observable<Response> {
const options = this.headers();
return this.http.get(`${environment.ApiUrl}/Roles/getRole`,options)
.map(res => res.json())
.catch(res => Observable.throw(res.json()));
}
I am trying to subscribe to the getUserRole() function, then assign the response to this.role but that is not happening, role is always undefined. when i do a ...subscribe(res => console.log(res)) i see the response data.
You have to wait the result of the async HTTP Request before check if can activate that route or not.
Try returning a new Observable instead:
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
return new Observable(observer => {
//
this.accountService.getUserRole().subscribe(role => {
//
if (role === 'admin') {
observer.next(true); // Allowing route activation
} else {
observer.next(false); // Denying route activation
}
}, err => observer.next(false));
});
}
i'm doing a login service. But i'm only capable of doing login, but i want to make a session to control the login's.
Where is my login.component.ts:
#Component({
selector: 'login',
templateUrl: './app/login/login.component.html'
})
export class LoginComponent implements OnInit {
model: any = {};
loading = false;
returnUrl: string;
constructor(
private route: ActivatedRoute,
private router: Router,
private utilizadorService: UtilizadoresService,
private alertService: AlertService) { }
ngOnInit() {
// reset login status
this.utilizadorService.logout();
this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/';
}
login() {
console.log("Login! ");
this.loading = true;
this.utilizadorService.login(this.model.email, this.model.password).subscribe(
data => {
this.alertService.success('Login successful', true);
this.router.navigate(['/profile']);
},
error => {
this.alertService.error(error._body);
this.loading = false;
});
}
}
and there is my utilizadores.serice.ts, where is the login/register function:
#Injectable()
export class UtilizadoresService {
constructor(private _http: Http) {}
private RegenerateData = new Subject<number>();
// Observable string streams
RegenerateData$ = this.RegenerateData.asObservable();
AnnounceChange(mission: number) {
this.RegenerateData.next(mission);
}
LoadData(): Promise<IUtilizadores[]> {
return this._http.get('/api/utilizadores')
.toPromise()
.then(response => this.extractArray(response))
.catch(this.handleErrorPromise);
}
Add(model: IUtilizadores) {
let headers = new Headers({
'Content-Type':
'application/json; charset=utf-8'
});
let options = new RequestOptions({ headers: headers });
delete model["id"];
let body = JSON.stringify(model);
return this._http.post('/api/utilizadores/', body, options).toPromise().catch(this.handleErrorPromise);
}
Update(model: IUtilizadores) {
let headers = new Headers({
'Content-Type':
'application/json; charset=utf-8'
});
let options = new RequestOptions({ headers: headers });
let body = JSON.stringify(model);
return this._http.put('/api/utilizadores/', body, options).toPromise().catch(this.handleErrorPromise);
}
Delete(id: number) {
return this._http.delete('/api/utilizadores/?id=' + id).toPromise().catch(this.handleErrorPromise);
}
login(email: string, password: string) {
return this._http.post('/api/utilizadores/login', { email: email, password: password })
.map((response: Response) => {
let utilizador = response.json();
if (utilizador) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(utilizador));
}
});
}
logout() {
// remove user from local storage to log user out
// localStorage.removeItem('id_token');
localStorage.removeItem('currentUser');
}
public authenticated() {
// Check if there's an unexpired JWT
// This searches for an item in localStorage with key == 'id_token'
return tokenNotExpired();
}
protected extractArray(res: Response, showprogress: boolean = true) {
let data = res.json();
return data || [];
}
protected handleErrorPromise(error: any): Promise<void> {
try {
error = JSON.parse(error._body);
} catch (e) {
}
let errMsg = error.errorMessage
? error.errorMessage
: error.message
? error.message
: error._body
? error._body
: error.status
? `${error.status} - ${error.statusText}`
: 'unknown server error';
console.error(errMsg);
return Promise.reject(errMsg);
}
}
export interface IUtilizadores {
id: number,
email: string,
nickname: string,
password: string
}
I'm doing this for a school project, so i dont want to work with Auth0, and i'm using VS 2015 and microsoft SQL server
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.