I have created a Common provider for the ionic app and i want to verify that user is logged in or not
so i have created a function verify to check if token exists or not but after verifying that token is null i want to setRoot page to login or register page so i used navcontroller to set Root Page but after running server it shows error
Error
ERROR Error: Uncaught (in promise): Error: StaticInjectorError(AppModule)[Content -> NavController]:
StaticInjectorError(Platform: core)[Content -> NavController]:
NullInjectorError: No provider for NavController!
Error: StaticInjectorError(AppModule)[Content -> NavController]:
StaticInjectorError(Platform: core)[Content -> NavController]:
NullInjectorError: No provider for NavController!
at _NullInjector.get (VM1014 vendor.js:1377)
at resolveToken (VM1014 vendor.js:1675)
at tryResolveToken (VM1014 vendor.js:1617)
at StaticInjector.get (VM1014 vendor.js:1485)
at resolveToken (VM1014 vendor.js:1675)
at tryResolveToken (VM1014 vendor.js:1617)
at StaticInjector.get (VM1014 vendor.js:1485)
at resolveNgModuleDep (VM1014 vendor.js:11270)
at _createClass (VM1014 vendor.js:11311)
at _createProviderInstance$1 (VM1014 vendor.js:11281)
at _NullInjector.get (VM1014 vendor.js:1377)
at resolveToken (VM1014 vendor.js:1675)
at tryResolveToken (VM1014 vendor.js:1617)
at StaticInjector.get (VM1014 vendor.js:1485)
at resolveToken (VM1014 vendor.js:1675)
at tryResolveToken (VM1014 vendor.js:1617)
at StaticInjector.get (VM1014 vendor.js:1485)
at resolveNgModuleDep (VM1014 vendor.js:11270)
at _createClass (VM1014 vendor.js:11311)
at _createProviderInstance$1 (VM1014 vendor.js:11281)
at c (VM1012 polyfills.js:3)
at Object.reject (VM1012 polyfills.js:3)
at NavControllerBase._fireError (VM1014 vendor.js:51258)
at NavControllerBase._failed (VM1014 vendor.js:51251)
at VM1014 vendor.js:51298
at t.invoke (VM1012 polyfills.js:3)
at Object.onInvoke (VM1014 vendor.js:5134)
at t.invoke (VM1012 polyfills.js:3)
at r.run (VM1012 polyfills.js:3)
at VM1012 polyfills.js:3
common.ts (Provider File)
import { NavController } from 'ionic-angular';
import { Storage } from '#ionic/storage';
import { HttpClient } from '#angular/common/http';
#Injectable()
export class CommonProvider {
base_url : string = "http://192.168.1.198:3000/v1/";
constructor(public http: HttpClient,public storage:Storage,private
navctrl:NavController) {
console.log('Hello CommonProvider Provider');
}
registerUser(values) {
return this.http.post(this.base_url+'/signups', values);
}
loginUser(login) {
return this.http.post(this.base_url+'/login', login);
}
verify(){
this.storage.get('token').then((val)=>{
if(val == null){
this.navctrl.setRoot('LoginPage');
this.storage.set('page','LoginPage');
}
});
}
}
You can do something like this:
import { App } from 'ionic-angular';
#Injectable()
export class YourProvider {
constructor(private app: App) {}
yourVerifyFunction() {
this.app.getRootNav().setRoot('YourPage');
}
}
Cheers
Try adding this line of code
import { NavController } from 'ionic-angular';
You should not be using the navController in the provider. It should be in the .ts file of the respective page/component.
But, if you still want to use it, you have forgot to import the navController in your provider.
Add
import { NavController } from 'ionic-angular';
at the top and you are ready to go
Related
I'm trying to do what I think it's a stupid simple endpoint and some how it seems nestjs is not resolving the observable from Axios which results in the request hanging until it reaches the timeout.
I've stripped down my entire application to barebones, literally, in the pursuit of the issue and I still can't really find anything....
main.ts:
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(8080);
}
bootstrap();
app.module.ts:
import { Module } from '#nestjs/common';
import { AuthModule } from './auth/authModule';
#Module({
imports: [AuthModule],
})
export class AppModule {}
AuthModule.ts:
import { Module } from '#nestjs/common';
import { AuthController } from './controllers/auth.controller';
import { HttpModule } from '#nestjs/axios';
#Module({
controllers: [AuthController],
imports: [HttpModule],
})
export class AuthModule {}
Auth.controller.ts:
import { Controller, Post } from '#nestjs/common';
import { HttpService } from '#nestjs/axios';
import { Observable } from 'rxjs';
import { AxiosResponse } from 'axios';
#Controller('auth')
export class AuthController {
constructor(private httpService: HttpService) {}
#Post('/login')
login(): Observable<AxiosResponse<string>> {
console.log('hit');
return this.httpService.get<string>('http://auth-ms/health');
}
}
package.json:
"dependencies": {
"#liaoliaots/nestjs-redis": "^8.2.1",
"#metamask/eth-sig-util": "^4.0.0",
"#nestjs/axios": "^0.0.8",
"#nestjs/common": "^8.0.0",
"#nestjs/config": "^2.0.0",
"#nestjs/core": "^8.0.0",
"#nestjs/platform-express": "^8.0.0",
"#nestjs/typeorm": "^8.1.4",
"axios": "^0.27.2",
"faker": "^6.6.6",
"ioredis": "^5.0.3 || ^0.3.6",
"jsonwebtoken": "^8.5.1",
"jwt-decode": "^3.1.2",
"nestjs-ethers": "^1.0.1",
"nestjs-real-ip": "^2.1.0",
"pg": "^8.7.3",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"typeorm": "^0.3.6",
},
Any clue on what's going on here? I guess I'm missing something small and stupid but... can't really figure out what.
So, AxiosResponse is a complex data structure and contains circular dependencies.
So you need to map it because you can't return it like this (except if you use a lib that parse circular JSON)
So you need to map the observable to only get the data of the website.
#Post('/login')
login(): Observable<string> {
console.log('hit');
return this.httpService
.get<string>('http://auth-ms/health')
.pipe(map((v) => v.data));
}
The Observable class works like a Promise and it handles I/O commands asynchronously by default. To return the result from a gateway request, like you are trying to do, you'll need to resolve the Observable synchronously.
To do it, you need to use the firstValueFrom or lastValueFrom functions from rxjs lib to convert it to a Promise and await the response:
import { Controller, Post } from '#nestjs/common';
import { HttpService } from '#nestjs/axios';
import { Observable, firstValueFrom } from 'rxjs';
import { AxiosResponse } from 'axios';
#Controller('auth')
export class AuthController {
constructor(private httpService: HttpService) {}
#Post('/login')
async login(): Promise<string> {
const responseObserver = this.httpService.get<string>('http://auth-ms/health');
const response = await firstValueFrom(responseObserver);
return response.data;
}
}
Im having some issues with validation a jwt in nestjs. Alot of documentation and tutorials show how to create token etc. I just want to validate it and protect graphql resolvers.
In my jwt.strategy.ts i have this code:
import { Injectable } from '#nestjs/common';
import { ConfigService } from '#nestjs/config';
import { PassportStrategy } from '#nestjs/passport';
import { passportJwtSecret } from 'jwks-rsa';
import { ExtractJwt, Strategy } from 'passport-jwt';
#Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private configService: ConfigService) {
super({
secretOrKeyProvider: passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: 'xxxxx',
}),
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
audience: 'urn:microsoft:userinfo',
issuer: 'xxxxx',
algorithms: ['RS256'],
});
}
validate(payload: unknown): unknown {
return payload;
}
}
And in my authz module i have:
import { Module } from '#nestjs/common';
import { PassportModule } from '#nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
#Module({
imports: [PassportModule.register({ defaultStrategy: 'jwt' })],
providers: [JwtStrategy],
exports: [PassportModule],
})
export class AuthzModule {}
In my resolvers i use the UseGuards decorator:
#UseGuards(AuthGuard('jwt'))
All this should work, but i get an error:
TypeError: Cannot read properties of undefined (reading 'logIn')
I dont want to do any login, just validate the token.
ANy tips on this? Have tried google, been at it for hours. Thanks!
I have build an interceptor for making HTTP requests to a PHP backend.
This backend gives an JWT token to the app and I save this in the Ionic Storage.
But I want to get that token from Storage and add it as an header to the HTTP request.
Below is my interceptor with and hardcoded token.
This works and I get a response from the backend.
See update # bottom of this post
http-interceptor.ts
import { HttpInterceptor, HttpRequest } from '#angular/common/http/';
import {HttpEvent, HttpHandler} from '#angular/common/http';
import { AuthProvider } from "../providers/auth/auth";
import {Injectable} from "#angular/core";
import {Observable} from "rxjs/Observable";
import {Storage} from "#ionic/storage";
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const changedReq = req.clone({headers: req.headers.set('Authorization', 'Bearer MY TOKEN')});
return next.handle(changedReq);
}
}
But how do I get the token from storage into the header.
I searched alot and most of the tutorials / examples are from the older HTTP module. If someone has an idea or has a up2date example ?
UPDATE
Oke below code send the token
intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>>{
return fromPromise(this.Auth.getToken())
.switchMap(token => {
const changedReq = req.clone({headers: req.headers.set('Authorization', 'Bearer ' + token )});
return next.handle(changedReq);
});
}
With 1 exception, namely the first time I access that page :)
You can save JWT token in, for example, localStorage
localStorage.setItem('myToken', res.token);
and then access it with
localStorage.getItem('myToken');
In your case something like this:
import { HttpInterceptor, HttpRequest } from '#angular/common/http/';
import {HttpEvent, HttpHandler} from '#angular/common/http';
import { AuthProvider } from "../providers/auth/auth";
import {Injectable} from "#angular/core";
import {Observable} from "rxjs/Observable";
import {Storage} from "#ionic/storage";
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const changedReq = req.clone({headers: req.headers.set('Authorization', localStorage.getItem('myToken'))});
return next.handle(changedReq);
}
}
If you want to use Ionic Storage
import { HttpInterceptor, HttpRequest } from '#angular/common/http/';
import {HttpEvent, HttpHandler} from '#angular/common/http';
import { AuthProvider } from "../providers/auth/auth";
import {Injectable} from "#angular/core";
import {Observable} from "rxjs/Observable";
import {Storage} from "#ionic/storage";
#Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(public _storage: Storage) {
_storage.get('myToken').then((val) => {
console.log('Your age is', val);
});
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const changedReq = req.clone({headers: req.headers.set('Authorization', this.val)});
return next.handle(changedReq);
}
}
Caching the token in the interceptor is a bad idea because if the token changes the interceptor will not be aware of those changes.
// Don't do this.
token: string;
constructor(private storage: Storage) {
this.storage.get('token').then((res) => {
this.token = res;
})
}
If you want to use Ionic Storage and the interceptor together you can do so by using Observable.flatMap like so...
app.module.ts
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true},
SecurityStorageService
]
AuthInterceptor.ts
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(
private securityStorageService: SecurityStorageService
) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// This method gets a little tricky because the security token is behind a
// promise (which we convert to an observable). So we need to concat the
// observables.
// 1. Get the token then use .map to return a request with the token populated in the header.
// 2. Use .flatMap to concat the tokenObservable and next (httpHandler)
// 3. .do will execute when the request returns
const tokenObservable = this.securityStorageService.getSecurityTokenAsObservable().map(token => {
return request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
});
return tokenObservable.flatMap((req) => {
return next.handle(req).do((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
// do stuff to the response here
}
}, (err: any) => {
if (err instanceof HttpErrorResponse) {
if (err.status === 401) {
// not authorized error .. do something
}
}
});
})
}
security-storage-service.ts
You technically don't need this service, but you shouldn't have Ionic Storage logic in your interceptor.
#Injectable()
export class SecurityStorageService {
constructor(private storage: Storage) {
}
getSecurityToken() {
return this.storage.get(StorageKeys.SecurityToken)
.then(
data => { return data },
error => console.error(error)
);
}
getSecurityTokenAsObservable() {
return Observable.fromPromise(this.getSecurityToken());
}
}
storage-keys.ts
export class StorageKeys {
public static readonly SecurityToken: string = "SecurityToken";
}
For anyone who comes across this like me and is using rxjs >=5.5.0 then you can just do:
auth-interceptor.ts
#Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private authService: AuthService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return from(this.authService.getToken()).pipe(mergeMap((token) => {
const changedReq = req.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
return next.handle(changedReq);
}));
}
auth-service.ts
public async getToken() {
return await this.storage.get('ACCESS_TOKEN');
}
I am creating a simple sample auth app with Ionic 2 and angularfire 2 as backend, when i try to create new user it says:
EXCEPTION: Error: Uncaught (in promise): Error: The specified
authentication provider is not enabled for this Firebase.
But i already enabled firebase authentication in firebase console:
app.ts
import {App, Platform} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
import {HomePage} from './pages/home/home';
import { FIREBASE_PROVIDERS, defaultFirebase, firebaseAuthConfig, AuthProviders, AuthMethods } from 'angularfire2';
#App({
template: '<ion-nav [root]="rootPage"></ion-nav>',
providers: [
FIREBASE_PROVIDERS,
defaultFirebase('https://samplequizapp-50eb5.firebaseio.com'),
firebaseAuthConfig({
provider: AuthProviders.Password,
method: AuthMethods.Password
})
],
config: {} // http://ionicframework.com/docs/v2/api/config/Config/
})
export class MyApp {
rootPage: any = HomePage;
constructor(platform: Platform) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
});
}
}
home.ts
import { Page } from 'ionic-angular';
import { AngularFire, FirebaseListObservable } from 'angularfire2';
import { OnInit } from '#angular/core'
#Page({
templateUrl: 'build/pages/home/home.html'
})
export class HomePage implements OnInit {
user: any = {};
data: FirebaseListObservable<any[]>;
constructor(private af: AngularFire) {
}
ngOnInit() {
this.data = this.af.database.list('/userId')
}
signUp(data) {
this.af.auth.createUser({
email: data.email,
password: data.password
})
}
}
I am pretty sure there is nothing wrong with my code:
Firebase2 in its current version (2.4.2) is not yet compatible with Firebase SDK v3, and all projects created with the new Firebase console are only accessible with calls comaptible with SDK v3.
You want to create your Firebase backend in the legacy console www.firebase.com first, and then migrate to the new console.
This is documented in this closed issue of the angularfire2 github: https://github.com/angular/angularfire2/issues/189
I am using Angular 2.0.0-beta.15. I am trying to get data from service in a component. Following is the piece of code in component.
import {Component} from 'angular2/core';
import {UserService} from '../services/user.service';
#Component({
selector: 'parent',
templateUrl: './views/parentUser.html',
providers: [UserService]
})
export class ParentUserComponent {
constructor(private _userService:UserService) {
this._userService.getCurrentUser().subscribe(data => console.log(data));
}
}
Now my UserService piece of code is
import {Injectable} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
#Injectable()
export class UserService {
private currentUser = {
username: '',
role: '',
targetURL: ''
};
setCurrentUser(currentUser) {
this.currentUser.username = currentUser.username;
this.currentUser.role = currentUser.role;
this.currentUser.targetURL = currentUser.targetURL;
console.log('current User:' + JSON.stringify(this.currentUser));
}
getCurrentUser() {
return Observable.of(this.currentUser);
}
}
My boots.ts is as follows:
///<reference path="../../node_modules/angular2/typings/browser.d.ts"/>
import {bootstrap} from 'angular2/platform/browser';
import {provide} from 'angular2/core';
import {ROUTER_PROVIDERS, ROUTER_DIRECTIVES, RouteConfig, Location, LocationStrategy, HashLocationStrategy} from 'angular2/router';
import {AppComponent} from './app.component';
import {HTTP_PROVIDERS} from 'angular2/http';
import {UserService} from './services/user.service';
import 'rxjs/Rx';
bootstrap(AppComponent, [ROUTER_PROVIDERS, HTTP_PROVIDERS, provide(LocationStrategy, {useClass: HashLocationStrategy}), UserService]);
Now when i try to run my component. it throws error like
Error: Uncaught (in promise): No provider for a!
angular2-polyfills.js:528 Unhandled Promise rejection: No provider for a!
NoProviderError {message:"No provider for a!, stack: "Error: DI Exception↵ at NoProviderError.BaseExc…odules/angular2/bundles/angular2.dev.js:11788:19)", keys: Array[3], injectors: Array[3]}
Can somebody guide me?