CRUD : update method doesn't work [Angular] - javascript

I faced an issue with update method. I'm working on a spring boot angular project so update doesnt work on frontend my code looking logic can someone gie me an idea about this issue
user.service
updateProfile(userData: SignUpData, id: string ): Observable<any> {
return this.http.patch( API_URL + 'update/' + id, userData, httpOptions);
}
component.ts
form: any = {};
id: string;
errorMessage = '';
currentUser: any;
constructor(private userservice: UserService, private route: ActivatedRoute, private router: Router, private token: TokenStorageService) { }
ngOnInit() {
this.currentUser = this.token.getUser();
}
onSubmit() {
const {adresse1, ...rest} = this.form;
const userData: SignUpData = {...rest, adresses: [adresse1]};
this.userservice.updateProfile(userData, this.currentUser.id).subscribe(
data => {
console.log(data);
},
err => {
this.errorMessage = err.error.message;
}
);
}
Interceptor.ts
export class AuthInterceptor implements HttpInterceptor {
constructor(private token: TokenStorageService) { }
intercept(req: HttpRequest<any>, next: HttpHandler) {
let authReq = req;
const token = this.token.getToken();
if (token != null) {
authReq = req.clone({ headers: req.headers.set(TOKEN_HEADER_KEY, 'Bearer ' + token) });
}
return next.handle(authReq);
}
}
export const authInterceptorProviders = [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true }
];

I try to logout & log in and that's working because first I didn't get user id so I add this.currentUser = this.token.getUser(); without refresh authenticate so GET was always returning 401 not found. I hope this answer can help people that have the same issue And thank you guys for your replies

Related

How to get user data in Angular after login

What I want to do is to get the user data and output it anywhere on my website. For example I would like to get the name for the user and output it on the homepage when the user is logged in.
any ideas ? Thanks
AuthService
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { EnvironmentUrlService } from './environment-url.service';
import { UserRegistrationDto } from '../models/user/UserRegistrationDto.model';
import { RegistrationResponseDto } from '../models/user/response/RegistrationResponseDto.model';
import { UserAuthenticationDto } from '../models/user/UserAuthenticationDto.model';
import { AuthResponseDto, user } from '../models/user/response/AuthResponseDto.model';
import { Subject, BehaviorSubject, Observable, map } from 'rxjs';
import { JwtHelperService } from '#auth0/angular-jwt';
#Injectable({
providedIn: 'root'
})
export class AuthenticationService {
private authChangeSub = new Subject<boolean>()
public authChanged = this.authChangeSub.asObservable();
constructor(private http: HttpClient, private envUrl: EnvironmentUrlService, private jwtHelper: JwtHelperService) {}
public registerUser = (route: string, body: UserRegistrationDto) => {
return this.http.post<RegistrationResponseDto> (this.createCompleteRoute(route, this.envUrl.urlAddress), body);
}
public loginUser = (route: string, body: UserAuthenticationDto) => {
return this.http.post<AuthResponseDto>(this.createCompleteRoute(route, this.envUrl.urlAddress), body);
}
public sendAuthStateChangeNotification = (isAuthenticated: boolean) => {
this.authChangeSub.next(isAuthenticated);
}
public logout = () => {
sessionStorage.removeItem("token");
this.sendAuthStateChangeNotification(false);
}
public isUserAuthenticated = (): boolean => {
const token = sessionStorage.getItem("token");
return token && !this.jwtHelper.isTokenExpired(token);
}
private createCompleteRoute = (route: string, envAddress: string) => {
return `${envAddress}/${route}`;
}
}
login.component.ts
loginUser = (loginFormValue: any) => {
this.showError = false;
const formValues = {... loginFormValue };
const userForAuth: UserAuthenticationDto = {
email: formValues.email,
password: formValues.password
}
this.authService.loginUser('api/accounts/login', userForAuth)
.subscribe({
next: (res:AuthResponseDto) => {
sessionStorage.setItem("token", res.token);
this.authService.sendAuthStateChangeNotification(res.isAuthSuccessful);
this.notificationService.showNotification('success','Login successfully')
this.router.navigate([this.returnUrl]);
},
error: (err: HttpErrorResponse) => {
this.errorMessage = err.message;
this.showError = true;
}})
}
**AuthResponse & User **
export interface AuthResponseDto {
isAuthSuccessful: boolean;
errorMessage: string;
token: string;
}
export interface user {
userId: string;
userName: string
firstName: string;
lastName: string;
role: string []
}
`
I can successfully register and log in a user. I can get the user data from the token but can't map it to user interface
You have to subscribe the api or function user login to get the user information. Also the local storage key value pairing is not used properly here. check user login function, it shows this. set Token(Users[0].
If the data is available in the token received, you can extract it after login and retrieve it with a getter method that return user if user is authenticated, null otherwise (or using promises, that would be cleaner).
The getter method retrieves the data stored in the token of the sessionStorage (if exists) and returns it formatted as user interface. Then you can access the user data fron any component, just import the service in the constructor and call the getter to get the data.

NestJS Interceptor - Append data to incoming request Header or Body

I am trying to modify an NestJS incoming request and append some data either to header or Body. I was able to replace all the body data with my data but i would like to append and not remove the incoming body data.
Here is the code i have
export class MyInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest();
const token = request.headers['authorization'];
if (token) {
const decoded = jwt_decode(token);
request.body['userId'] = decoded['id'];
}
return next.handle();
}
}
Thanks in advance
I have added two examples as after running testing for the interceptor, it passed without any issue. Of course, my example will be very different to your set up, however, hopefully it'll give you enough insight:
The test file:
test('should not mutate entire request body object', () => {
const dto = {
username: 'testuser',
email: 'test#domain.com',
};
const headers = {
authorization: 'Bearer sdkfjdsakfjdkjfdal',
};
return request(app.getHttpServer())
.post('/')
.send(dto)
.set(headers)
.expect(({ body }) => {
expect(body.userId).toBeDefined();
delete body.userId;
expect(body).toStrictEqual(dto);
});
});
I understand your problem as attempting to obtain information about the authenticated user, and return it/use it later on? However, your current implementation seems to completely override the request.body instead of append your property to the original object.
Interceptor:
#Injectable()
export class HttpRequestBodyInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable {
const request = context.switchToHttp().getRequest();
const token = request.headers['authorization'];
if (token) {
// decode token
request.body['userId'] = 'user_123456789';
}
return next.handle();
}
}
Controller:
#Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
#Post()
#UseInterceptors(HttpRequestBodyInterceptor)
getHello(#Req() req): string {
return req.body;
}
}
This returns the correct response and the test will pass. However, you may find a more robust solution would be:
#Injectable()
export class HttpRequestBodyInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable {
const request = context.switchToHttp().getRequest();
const token = request.headers['authorization'];
if (token) {
// decode token
request.userId = 'user_123456789';
}
return next.handle();
}
}
And then access this in your controller by:
#Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
#Post()
#UseInterceptors(HttpRequestBodyInterceptor)
getHello(#Req() req) {
return {
userId: req.userId,
...req.body,
};
}
}
Finally, if your only need for an interceptor is to obtain that userId property, you may find that https://docs.nestjs.com/security/authentication#jwt-functionality is useful.
#Injectable()
export class JwtInterceptor implements NestInterceptor {
constructor(private readonly jwtService: JwtService, private readonly
userService: UserService) { }
async intercept(context: ExecutionContext, next: CallHandler):
Promise<Observable<any>> {
var request: WsArgumentsHost = context.switchToWs();
var { handshake: { headers: { authorization } } } =
request.getClient();
try {
var jwt = authorization.split(" ")[1];
var { phone } = await this.jwtService.verify(jwt, jwtConstraints)
var user: User = await this.userService.findUserByPhoneNumber(phone);
request.getData()["user"]=user;
return next.handle().pipe(map((data) => { return { ...data, 'user': "david" }; }));
i hope this will help someone in future while working with socket.i wanted the user object in the body after they pass authentication .the above trick worked out for me

User is Null when using a Service over UserManager

Using Angular 7 and OIDC-Client I created an AuthService that exposes a few UserManager methods.
When I call signInRedirectCallback from the AuthService the user is null.
If I call it using UserManager directly the user is not null.
More details below:
const settings : UserManagerSettings = {
authority: 'https://localhost:5005',
client_id: 'spa',
redirect_uri: 'https://localhost:5001/signin',
post_logout_redirect_uri: 'https://localhost:5001/signout',
response_mode: 'query',
response_type: 'code',
scope: 'openid profile email offline_access api',
filterProtocolClaims: true,
loadUserInfo: true
};
#Injectable({
providedIn: 'root'
})
export class AuthService {
private manager = new UserManager(settings);
private user: User = null;
constructor() {
this.manager.getUser().then(user => {
this.user = user;
});
}
isSignedIn(): boolean {
return this.user != null && !this.user.expired;
}
getClaims(): any {
return this.user.profile;
}
signInRedirect(args?: any): Promise<void> {
return this.manager.signinRedirect(args);
}
signInRedirectCallback(url?: string): Promise<void> {
return this.manager.signinRedirectCallback(url).then(user => {
this.user = user;
});
}
// Other methods
}
I have an AuthenticateGuard as follows:
export class AuthenticatedGuard implements CanActivate {
constructor(private authService: AuthService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : boolean {
if (this.authService.isSignedIn())
return true;
this.authService.signInRedirect({ state: { url: state.url }});
return false;
}
}
Then my callback component is the following:
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../shared/services/auth.service'
import { UserManagerSettings, UserManager } from 'oidc-client';
import { Router, ActivatedRoute } from '#angular/router';
#Component({
selector: 'signin',
templateUrl: './signin.component.html'
})
export class SignInComponent implements OnInit {
private manager = new UserManager(settings);
constructor(private authService: AuthService, private router: Router) { }
ngOnInit() {
this.manager.signinRedirectCallback().then(function (user) {
console.log(user);
});
}
}
On the callback component user is undefined when I use console.log(user).
To make this work I needed to create a new UserManager on the SignInComponent (Callback Component) instead of using the AuthService, e.g.:
const settings : UserManagerSettings = {
authority: 'https://localhost:5005',
client_id: 'spa',
redirect_uri: 'https://localhost:5001/signin',
post_logout_redirect_uri: 'https://localhost:5001/signout',
response_mode: 'query',
response_type: 'code',
scope: 'openid profile email offline_access api',
filterProtocolClaims: true,
loadUserInfo: true
};
#Component({
selector: 'signin',
templateUrl: './signin.component.html'
})
export class SignInComponent implements OnInit {
private manager = new UserManager(settings);
constructor(private router: Router) { }
ngOnInit() {
this.manager.signinRedirectCallback().then(function (user) {
console.log(user);
});
}
}
Any idea why this happens? What am I missing?
Thank You
Few thing to try
Change your response_type to this
response_type: 'id_token token'
and remove null in user
private user: User;
and remove these 2
response_mode
#Injectable({
providedIn: 'root'
})
2 things to check:
First, open the browser's console and see if the signinRedirectCallback() call is throwing any errors.
Second, look in the application's session storage, do you see any user data populated by the authentication flow?
Another observation: you should not create instances of UserManager for every page; All the logic for oauth with oidc-client should be encapsulated in
a service that will be injected in the different pages of the application.
Change the isSignedIn method to promise-based.
isSignedIn(): Promise<boolean> {
return new Promise((resolve, reject) => {
this.manager.getUser().then(user => {
resolve(user != null && !user.expired);
});
});
}
And your route guard:
canActivate(): Promise<boolean> {
return new Promise((resolve, reject) => {
this.authService.isLoggedIn().then(result => {
if (result) {
resolve(result);
} else {
this.authService.startAuthentication().finally(() => {
reject(false);
});
}
});
});
}

Error when using resolve with http requests in Angular 4

I am trying to use resolve for prefetching a http request in my Angular 4 project, but its throwing a ERROR Error: Uncaught (in promise): Response with status whenever there is an error response from Node server. The code works fine when there is a success http code like 200. Here's the resolve code I am working on:
#Injectable()
export class LoginResolverService implements Resolve<Object> {
constructor(private http: Http) {
}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Object> | Promise<Object> | Object {
const headers = new Headers({'Content-Type': 'application/json'});
return this.http.get('http://localhost:3000/login_check', {headers: headers})
.map((response: Response) => {
return response.json();
}).catch((error: Response) => Observable.throw(error.json()));
}
}
Component file code:
loginState: Observable<Object>;
constructor(private route: ActivatedRoute, private router: Router) { }
ngOnInit() {
this.route.data.subscribe((data: Data) => {
this.loginState = data['isLoggedin'];
this.loginState.subscribe((response: any) => {
console.log(response);
}, (error: any) => {
console.log(error)
})
});
}
Routes related code:
{path: 'notifications', loadChildren: './notifications/notifications.module#NotificationsModule', resolve: {isLoggedin: LoginResolverService}}
Please help me solve this issue, as I couldn't find any proper information about using resolve with http
In my resolver service, I call a separate data service to actually get the data:
resolve(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<IProduct> {
let id = route.paramMap.get('id');
if (isNaN(+id)) {
console.log(`Product id was not a number: ${id}`);
this.router.navigate(['/products']);
return Observable.of(null);
}
return this.productService.getProduct(+id)
.map(product => {
if (product) {
return product;
}
console.log(`Product was not found: ${id}`);
this.router.navigate(['/products']);
return null;
})
.catch(error => {
console.log(`Retrieval error: ${error}`);
this.router.navigate(['/products']);
return Observable.of(null);
});
}
Then in the component:
ngOnInit(): void {
this.product = this.route.snapshot.data['product'];
}
That's it!
Or if you expect that the resolved data property will change without changing the route (not including user edits to that data), then you can use:
ngOnInit(): void {
this.route.data.subscribe(data => {
this.product = data['product'];
});
}
The router itself calls the resolver and handles the subscription. So you don't have to.

Angular 2 - Cannot instantiate cyclic dependency

I create custom XHRBackend class to catch 401 error globally. In AuthService I have 2 methods which use http - login and refreshToken. So i have dependency chain like that: Http -> customXHRBackend -> AuthService -> Http. How can I fix this?
export class CustomXHRBackend extends XHRBackend {
constructor(browserXHR: BrowserXhr,
baseResponseOptions: ResponseOptions,
xsrfStrategy: XSRFStrategy,
private router: Router,
private authService: AuthService) {
super(browserXHR, baseResponseOptions, xsrfStrategy);
}
createConnection(request: Request): XHRConnection {
let connection: XHRConnection = super.createConnection(request);
connection.response = connection.response
.catch(this.handleError.bind(this));
return connection;
}
handleError(error: Response | any) {
console.log('ERROR',error['status']);
if(error['status'] === 401) {
this.authService.logout();
this.router.navigate(['/']);
}
return Observable.throw(error);
}
}
AuthService.ts
#Injectable()
export class AuthService {
private loggedIn: boolean = false;
constructor(private http: Http) {
this.loggedIn = !!localStorage.getItem('authToken');
}
login(email: string, password: string): Observable<Response> {
let headers: Headers = new Headers();
headers.set('Content-Type', 'application/json');
return this.http.post('https://httpbin.org/post',
{
email: email,
password: password
},
{
headers: headers
})
.map((response) => {
let res = response.json();
// if (res['success']) {
if (res) {
localStorage.setItem('authToken', res['token']);
localStorage.setItem('refreshToken', res['refreshToken']);
console.log('logged');
this.loggedIn = true;
}
return response;
}
);
}
logout(): void {
localStorage.removeItem('authToken');
this.loggedIn = false;
console.log('Logged out');
}
isLogged(): boolean {
return this.loggedIn;
}
refreshToken(): Observable<Response> {
let headers: Headers = new Headers();
headers.set('token', localStorage.getItem('token'));
headers.set('refreshToken', localStorage.getItem('refreshToken'));
return this.http.get('https://httpbin.org/get', {
headers: headers
});
}
}
Include CustomXHRBackend in app.module.ts
{
provide: XHRBackend,
useFactory: (browserXHR: BrowserXhr,
baseResponseOptions: ResponseOptions,
xsrfStrategy: XSRFStrategy,
router: Router,
authService: AuthService) => {
return new CustomXHRBackend(browserXHR, baseResponseOptions, xsrfStrategy, router, authService);
},
deps: [BrowserXhr, ResponseOptions, XSRFStrategy, Router, AuthService]
}
How about HTTP Interceptors... There's a blog post here.
If you Google you'll find more...
Here's how you hook one into you App Module
you can clone the request in you interceptor and add X-CustomAuthHeader into headers etc.
Please see in your constructor where you inject dependency. You can't inject in a few Services the same dependency.Example: CustomXHRBackend => AuthService, AuthService => CustomXHRBackend

Categories

Resources