How to do the Flattening in Rxjs for Angular Auth Service? - javascript

I have created a Authentication service in Angular with function SignUp that sends the API Request to Firebase, As Firebase returns the User ID, I am saving the userid into my personal MongoDB Database with its Role. Now the problem here is i am sending two request which i want to further Subscribed in Register.component.ts, I am not able to understand how to achieve this. Below are the sample code that i have tried.
auth.service.ts
signUp(email: string, password: string) {
return this.http.post<AuthResponse>(`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${config.API_KEY}`, {
email: email,
password: password,
returnSecureToken: true
}).pipe(
switchMap(data => {
return this.http.post<any>(`${config.BASE_URL}/api/ezusers/`,{useruid: data.idToken, 'isRegistered':false}); // or this.userId
})
).map(response => {
this.authenticatedUser(response.email, response.localId, response.idToken, +response.expiresIn);
// this.userOrders = response;
return
});
}
Register.component.ts
onSubmit() {
this.loading = true;
if (this.registerForm.valid) {
this._authService.signUp(this.registerForm.value.email, this.registerForm.value.password).subscribe(
res => {
console.log(res);
this.loading = false;
this.registerForm.reset();
this.success = true;
this.error = false;
},
err => {
console.log(err);
this.loading = false;
this.success = false;
this.error = this.errMsgs[err.error.error.message];
})
}
else {
}
}
Any help would be really Appreciated.
Thanks in Advance!

I'm not totally understand what you want to achieve in register component, but what's I've noticed there always response will be falsy, as you return undefined in service. Not sure what method authenticatedUser returns, but try it.
signUp(email: string, password: string) {
return this.http.post<AuthResponse>(`https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=${config.API_KEY}`, {
email: email,
password: password,
returnSecureToken: true
}).pipe(
switchMap(data => {
return this.http.post<any>(`${config.BASE_URL}/api/ezusers/`,{useruid: data.idToken, 'isRegistered':false}); // or this.userId
})
).map(response =>
this.authenticatedUser(response.email, response.localId, response.idToken, +response.expiresIn)
);

Related

Fetching APIs while doing full-stack dev

I'm having trouble when I'm fetching my APIs that are created on the backend.
Mostly, I'm handling everything right on the good side but not when there is an error because the catch(error) method only catches the errors that are in the front-end server while my errors are coming from my back-end. My stack is mostly focused on VueJS and Spring Boot. I can give an example to clarify things.
For example, in the login. I have a controller in my backend that contains JWT Creation
JwtUtils jwtUtils;
#PostMapping("/signin")
public ResponseEntity<?> authenticateUser(#Valid #RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getEmail(),
roles));
}
on the front-end side I just consume this API.
So, I created a service on VueJS and that service is consumed by one of my views on a button click.
My service :
class AuthService{
login(user){
return fetch("http://localhost:100/api/v1/auth/signin",
{method : "POST",
headers:{
"Content-type" : "application/json"
},
body: JSON.stringify({
email:user.email,
password: user.password,
}),
}).then( response => response.json()).then(data =>{
if (data.accessToken){
localStorage.setItem('user',JSON.stringify(data))
}
return data})
}
logout(){
localStorage.removeItem('user')
}
}
export default new AuthService();
That service is called by my module (Vuex) in the localstore:
import AuthService from '../services/auth.service';
const user = JSON.parse(localStorage.getItem('user'));
const initialState = user
? { status: { loggedIn: true }, user }
: { status: { loggedIn: false }, user: null };
export const auth = {
namespaced: true,
state: initialState,
actions: {
login({ commit }, user) {
return AuthService.login(user).then(
user => {
commit('loginSuccess', user);
return Promise.resolve(user);
},
error => {
commit('loginFailure');
return Promise.reject(error);
}
);
},
logout({ commit }) {
AuthService.logout();
commit('logout');
},
register({ commit }, user) {
return AuthService.register(user).then(
response => {
commit('registerSuccess');
return Promise.resolve(response.data);
},
error => {
commit('registerFailure');
return Promise.reject(error);
}
);
}
},
mutations: {
loginSuccess(state, user) {
state.status.loggedIn = true;
state.user = user;
},
loginFailure(state) {
state.status.loggedIn = false;
state.user = null;
},
logout(state) {
state.status.loggedIn = false;
state.user = null;
},
registerSuccess(state) {
state.status.loggedIn = false;
},
registerFailure(state) {
state.status.loggedIn = false;
}
}
};
And finally I have a view that would call the action, its basically a form that contains 2 input fields that are going to be passed to the backend for the post method.
Login.vue :
<template>
<div id="nav">
<NavBar/>
<Loader v-if="loading"/>
<Form #clicked="onClickValue" :error="message" />
</div>
</template>
<script>
import NavBar from '../components/NavBar.vue'
import Form from '../components/Form.vue'
import Loader from '../components/Loader.vue'
export default {
components:{
NavBar,Form,Loader
},
data(){
return{
err:null,
loading:false,
message: '',
}
},
methods : {
onClickValue(user) {
this.loading = true;
this.$store.dispatch("auth/login", user).then(
() => {
this.$router.push("/token");
},
(error) => {
this.loading = false;
this.message =
(error.response &&
error.data &&
error.data.message) ||
error.message ||
error.toString();
}
);
},
},
}
</script>
I know that's alot of code but i'd like to explain my problem, basically I have some data on my server and when I fetch my API I want the user to login depending on his credentials. I know how to handle the errors but I don't know if that's the conventional way to do so. Generally I'd do this for example :
if res.status == 403 then (show error message on screen saying that the user is forbidden)
But is this how people handle errors that come from the backend ?? how should I do to handle my errors that are coming from the backend, is it an if statement or something else that should handle it (is what i'm doing even secure? )?
basically here is an image of my page.
Form
Its generally a good idea for the backend to handle the error messages, whenever they are generic or something specific, then on the frontend we just show that error message.
With this approach you wont struggle on the frontend in order to determinate which error code example: if res.status == 403 || res.status === 404.
The only thing you care about is error.message

How to get one data from database by id (MEAN Stack)?

I am creating an application in MEAN stack where you can upload properties to sell and rent. I want to create a page for every single uploaded property. For this, I need to get that property by id from the database. I can get it on the backend server, but I can't see it on the frontend. I upload the code, so you can understand it better.
the backend code, user.js
router.get("/:id", (req, res, next) => {
let loggedInUser;
User.findById(req.params.id).then(user => {
if (user) {
loggedInUser = user;
console.log(loggedInUser);
res.json({
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
phone: user.phone,
image: user.image,
jobTitle: user.jobTitle
});
} else {
res.status(404).json({ message: "User not found!" });
}
});
});
in the auth.service.ts
private userData: LoggedInUser;
getUser(id: string){
let loggedInUser: LoggedInUser;
this.http.get<{user: any}>("http://localhost:3000/api/user/" + id)
.subscribe(response => {
loggedInUser = response.user;
this.userData = loggedInUser;
});
console.log(this.userData);
}
Here I got undefined when I console.log it.
I just run the getUser method in the userhome.component.ts.
ngOnInit() {
this.authService.getUser(this.id);
}
I would really appreciate any help!
Since you have declared the object representation that matches the endpoint response, this code snippet should work perfectly fine. I suggest you try it out.
private userData: LoggedInUser;
getUser(id: string) {
this.http.get < LoggedInUser > ("http://localhost:3000/api/user/" + id)
.subscribe(response => {
this.userData = response.user;
console.log(this.userData);
});
}

hapi-auth-basic validate function doesn't work properly when the function contains asynchronous code

I am using hapi-auth-basic version 5.0.0 for authentication in my hapi server v17.2.2. It gives error when there is asynchronous code inside the validation function. What to do?
I used hapi-cli to create a hapi project. It has a folder called policies which contains the validate functions used for authentication.
I modified it a little bit to my convenience as follows
const Boom = require('boom');
const User = Models.User
module.exports = async (request, email, password, h) => {
if (!email || !password) {
return {
isValid: false,
credentials: null
}
}
User.findOne({
email,
role: 'admin'
}).exec((err, currentUser) => {
if (!currentUser || err) {
return Boom.badRequest('You must be admin user');
}
request.adminUser = currentUser;
return {
isValid: true,
credentials: currentUser
}
});
};
I want to authenticate the user if the given email address is present and the user role is admin
But I am getting the following error
Debug: internal, implementation, error
TypeError: Cannot destructure property `isValid` of 'undefined' or 'null'.
at Object.authenticate (/home/sruthi/IoTRL/hapi-api/node_modules/hapi-auth-basic/lib/index.js:64:56)
at <anonymous>
When I returned just {isValid: true, credentials: {email}} like this
module.exports = async (request, email, password, h) => {
if (!email || !password) {
return {
isValid: false,
credentials: null
}
}
return {
isValid: true,
credentials: {email}
}
};
without the asynchronous code getting the user from database, it worked fine.
Because your function returns nothing, Mongoose exec((err, user)) is out of your function's scope, and also you are already using async functions, why don't you use await syntax.
Here, a quick rewrite of your code.
module.exports = async (request, email, password, h) => {
if (!email || !password) {
return {
isValid: false,
credentials: null
}
}
try
{
const user = await User.findOne({ email, role: 'admin' }).exec();
// user doesn't exist
if(!user){
return Boom.unauthorized('You must be admin user');
}
// we found the user, let's authenticate
request.adminUser = currentUser;
return {
isValid: true,
credentials: currentUser
}
} catch(e){
// handle other errors
return Boom.badRequest(e);
}
};

Angular - Obeservable not working correctly

I have the following code that is not working correctly.
I have a service, which offers registration for a user.
register(firstname: string, lastname: string, email: string, password: string): Observable<boolean> {
let body = {firstname: firstname, lastname: lastname, email: email, password: password};
this.http.post(this.base_url + "api/register/user/", body)
.subscribe(
(data) => {
if((data as any).status == 'success') {
return Observable.of(true);
}
},
(error) => {
return Observable.of(false);
});
return Observable.of(false);
}
The register method is working correctly since the API where I'm registering the users is returning "success". The problem is when I'm calling it as follows:
registerUser(e) {
...
let isRegistered = false;
this.userService.register(firstname, lastname, email, password).subscribe(register => isRegistered = register);
if(isRegistered) {
console.log("isRegistered = true");
this.router.navigate(['/home']);
return true;
} else {
console.log("isRegistered = false");
return false;
}
}
I'm also importing the necessary modules:
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
"isRegister" is remaining false and as a result, the page is not redirecting to the home page.
Does anyone have an idea where the problem could be?
Thank you in advance!
The isRegistered value will always be false because you are treating an asynchronous operation like a synchronous one. Basically the check if (isRegistered) will run before you have acquired the value from your service. In order to avoid this, you have to move the checks inside of the subscription success callback:
this.userService
.register(firstname, lastname, email, password)
.subscribe(isRegistered => {
if (isRegistered) {
this.router.navigate(["/home"]);
return true;
} else {
return false;
}
});
In this way you will be sure that isRegistered's value has been set by the result of the service call.
Your register() function also has a flaw - you will always return an Observable of false. You probably want to return the result of the HTTP request. You should .map() the result of the HTTP response to a Boolean and subscribe when using the service.
register(firstname: string, lastname: string, email: string, password: string): Observable<boolean> {
const body = { firstname, lastname, email, password };
return this.http.post(this.base_url + 'api/register/user/', body)
.map(data => {
if((data as any).status === 'success') {
return Observable.of(true);
} else {
return Observable.of(false);
}
})
.catch(() => Observable.of(false));
}

angular2 http post request to get res.json()

I'm currently making simple user-authentication app.
now I'm done with backend process with node js and passport.
what I've done was returning json response if authentication goes well or not.
router.post('/register', (req, res) => {
if(!utils.emailChecker(req.body.username)) {
return res.status(403).json({
error: "Invalid Username",
code: 403
});
}
if(!utils.passwordChecker(req.body.password)) {
return res.status(403).json({
error: "Invalid Password",
code: 403
});
}
//mysql query : variables must be inside "" or '';
let sql = `SELECT * FROM users WHERE username="${req.body.username}"`;
connection.query(sql, (err, result) => {
if(err) throw err;
if(utils.duplicateChecker(result)) {
return res.status(409).json({
error: "Username Exist",
code: 409
});
} else {
hasher({password: req.body.password}, (err, pass, salt, hash) => {
let user = {
authId: 'local: '+req.body.username,
username: req.body.username,
password: hash,
salt: salt,
displayName: req.body.displayName
};
let sql = 'INSERT INTO users SET ?';
connection.query(sql, user, (err, rows) => {
if(err) {
throw new Error("register error!");
} else {
req.login(user, (err) => {
req.session.save(() => {
return res.json({ success: true });
});
});
}
});
});
}
});
});
As you can see above, every time request makes error or goes perfect, json that contains error & code or success property is returned.
What I want to do is that getting these jsons via http service of angular2.
#Injectable()
export class UserAuthenticationService {
private loginUrl = "http://localhost:4200/auth/login";
private registerSuccessUrl = "http://localhost:4200/auth/register";
headers = new Headers({
'Content-Type': 'application/json'
});
constructor(private http: Http) { }
/*
body: {
username,
password,
}
*/
logIn(user: Object) {
return this.http
.post(this.registerSuccessUrl, JSON.stringify(user),
{ headers: this.headers });
}
What I've tried is this way. Make http post request using backend url.
and implement function on AuthComponent.
export class AuthComponent {
username: string = '';
password: string = '';
remembered: boolean = false;
submitted = false;
constructor(private userAuthenticationService: UserAuthenticationService) {}
onsubmit() {
this.userAuthenticationService.logIn({ username: this.username, password: this.password });
this.submitted = true;
}
}
But result is I just get json object on screen. { success: true }!
How can I get this json object thru http call and make use of 'success' property?
You are not using the server's response.
onsubmit() {
this.userAuthenticationService
.logIn({ username: this.username, password: this.password })
.subscribe(result => {
//here check result.success
}, error => console.error(error));
this.submitted = true;
}
The Http calls are asynchronous. Hence, using something like :
const data =this.userAuthenticationService.logIn({ username: this.username, password: this.password }); would not work. Rather subcribe to the response like this :
this.userAuthenticationService.logIn({ username: this.username, password: this.password }).subscribe(
data => {
this.submitted = data.success;
});
Here data is the response object from the server.

Categories

Resources