Ionic 3 + HttpClientModule 和来自存储的令牌
Ionic 3 + HttpClientModule and token from storage
我已经构建了一个拦截器,用于向 PHP 后端发出 HTTP 请求。
这个后端为应用程序提供了一个 JWT 令牌,我将其保存在 Ionic Storage 中。
但我想从存储中获取该令牌并将其作为 header 添加到 HTTP 请求中。
下面是我的带有硬编码令牌的拦截器。
这行得通,我从后端得到了响应。
查看更新@底部 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);
}
}
但是如何将令牌从存储中获取到 header。
我搜索了很多,大部分教程/示例都来自旧的 HTTP 模块。如果有人有想法或有 up2date 示例?
更新
Oke 下面的代码发送令牌
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);
});
}
有 1 个例外,即我第一次访问该页面:)
您可以将 JWT 令牌保存在 localStorage
中
localStorage.setItem('myToken', res.token);
然后使用
访问它
localStorage.getItem('myToken');
在你的情况下是这样的:
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);
}
}
如果你想使用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);
}
}
在拦截器中缓存令牌不是一个好主意,因为如果令牌发生变化,拦截器将不会意识到这些变化。
// Don't do this.
token: string;
constructor(private storage: Storage) {
this.storage.get('token').then((res) => {
this.token = res;
})
}
如果你想同时使用 Ionic Storage 和拦截器,你可以像这样使用 Observable.flatMap...
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
}
}
});
})
}
安全存储-service.ts
从技术上讲,您不需要此服务,但您的拦截器中不应包含 Ionic Storage 逻辑。
@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());
}
}
存储-keys.ts
export class StorageKeys {
public static readonly SecurityToken: string = "SecurityToken";
}
对于像我一样遇到这种情况并正在使用 rxjs >=5.5.0 的人,您可以这样做:
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');
}
我已经构建了一个拦截器,用于向 PHP 后端发出 HTTP 请求。 这个后端为应用程序提供了一个 JWT 令牌,我将其保存在 Ionic Storage 中。 但我想从存储中获取该令牌并将其作为 header 添加到 HTTP 请求中。
下面是我的带有硬编码令牌的拦截器。 这行得通,我从后端得到了响应。
查看更新@底部 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);
}
}
但是如何将令牌从存储中获取到 header。 我搜索了很多,大部分教程/示例都来自旧的 HTTP 模块。如果有人有想法或有 up2date 示例?
更新
Oke 下面的代码发送令牌
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);
});
}
有 1 个例外,即我第一次访问该页面:)
您可以将 JWT 令牌保存在 localStorage
中 localStorage.setItem('myToken', res.token);
然后使用
访问它localStorage.getItem('myToken');
在你的情况下是这样的:
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);
}
}
如果你想使用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);
}
}
在拦截器中缓存令牌不是一个好主意,因为如果令牌发生变化,拦截器将不会意识到这些变化。
// Don't do this.
token: string;
constructor(private storage: Storage) {
this.storage.get('token').then((res) => {
this.token = res;
})
}
如果你想同时使用 Ionic Storage 和拦截器,你可以像这样使用 Observable.flatMap...
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
}
}
});
})
}
安全存储-service.ts
从技术上讲,您不需要此服务,但您的拦截器中不应包含 Ionic Storage 逻辑。
@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());
}
}
存储-keys.ts
export class StorageKeys {
public static readonly SecurityToken: string = "SecurityToken";
}
对于像我一样遇到这种情况并正在使用 rxjs >=5.5.0 的人,您可以这样做:
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');
}