アプリケーションをUATにデプロイしましたが、アクセス拒否(401)ページに直接移動するため、モバイルでアプリケーションを実行できません。アクセストークンの問題が原因だと思います。
私のアプリケーションを処理するために、主に2つのインターセプターがあります。1.エラーインターセプター-ルートエラーまたは不正なエラーが発生した場合に処理します。2.jwt-トークンを取得するために認証サービスを内部的に呼び出すトークンを割り当てます。
以下は、トークンを受信する準備ができているというpostMessageを送信することにより、セッションまたはローカルで、またはウィンドウイベントからアクセストークンを取得しようとしているサービスファイルです。
authentication-service.ts
public getToken() {
let accessToken = null;
const auth = JSON.parse(sessionStorage.getItem('auth'));
if (auth) {
accessToken = auth.access_token;
} elseif (accessToken == null || accessToken === undefined) {
accessToken = localStorage.getItem('access_token');
}
window.addEventListener('message', function(event){
// this event should have all the necessary tokens
}, false);
// once my page is loaded to indicate that I am ready to receive the message from server side.
parent.postMessage({ askForToken:"true"}, "*");
return accessToken;
}
window.addEventListenerを作成してデータを取得するためにparent.postMessageを送信していますが、イベントが期待どおりにトークンを送信していません。
私はauthentication.service.tsで上記のすべてのコード実装を行っていますが、それが正しい方法かどうかはわかりません。
このコードを実装してトークンを適切に受け取る正しい方法を誰かに提案してもらえますか?
トークンを使用した展開を初めて試みているので、修正してください。
ソースコードとデモ:
https://github.com/trungk18/angular-authentication-demo-with-lazy-loading
https://stackblitz.com/edit/angular-authentication-demo-with-lazy-loading
最初に実行するときに、他のすべてのモジュールを遅延ロードするセクションを追加します。つまり、ログインページのみが最初に読み込まれます。ログイン後、次のモジュールがロードされます。それは私たちに多くの帯域幅を節約します。
ユーザーがいて、ログインに成功した後、このオブジェクト全体をlocalStorageに保存します。
フローは次のようになります。
アプリケーションを開きます
AuthGuardがトリガーされます。トークンを持つユーザーオブジェクトがlocalStorageにある場合は、ルートをアクティブ化します。そうでない場合は、ログインページに戻ります。
ルートがアクティブ化され、サーバーへのAPI呼び出しを開始すると、JWTInterceptorがトリガーされ、後続の各要求でトークンが送信されます。
ErrorInterceptorは401があるかどうかを確認してから、localStorageからユーザーを削除し、ページをリロードします。誰かのユースケースでのこの処理は、別のトークンまたはオブジェクトでlocalStorageを手動で更新しようとします。サーバーからの修飾子がなくてもトークンが正しい場合、それは発生しないはずです。
モデル
export const ConstValue = {
ReturnUrl: "returnUrl",
CurrentUser: "currentUser",
}
export const ConstRoutingValue = {
Login: "login"
}
export interface AICreateUser {
firstName: string;
lastName: string;
email: string;
password: string;
roleIds: string[]
}
export interface PartnerUser extends AICreateUser {
id: string;
createdAt: string;
token: string;
featureSet: string[]
}
export interface AuthDto {
email: string;
password: string;
}
auth.service
export class AuthService {
private _currentUserSubject: BehaviorSubject<User>;
public currentUser: Observable<User>;
public get currentUserVal(): User {
return this._currentUserSubject.value;
}
get currentUserToken() {
return this.currentUserVal.token;
}
constructor(private http: HttpClient) {
this._currentUserSubject = new BehaviorSubject<User>(this.getUserFromLocalStorage());
this.currentUser = this._currentUserSubject.asObservable();
}
login(username, password) {
return this.http.post<any>(`/users/authenticate`, { username, password })
.pipe(map(user => {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem(ConstValue.CurrentUser, JSON.stringify(user));
this._currentUserSubject.next(user);
return user;
}));
}
logout() {
// remove user from local storage and set current user to null
localStorage.removeItem(ConstValue.CurrentUser);
this._currentUserSubject.next(null);
}
private getUserFromLocalStorage(): User {
try {
return JSON.parse(localStorage.getItem(ConstValue.CurrentUser)!);
} catch (error) {
return null!;
}
}
}
そして、リクエストごとにヘッダーにトークンを追加するJwtInterceptorがあります
export class JwtInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthService) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
let currentUser = this.authenticationService.currentUserVal;
if (currentUser && currentUser.token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${currentUser.token}`
}
});
}
return next.handle(request);
}
}
export const JWTInterceptorProvider = {
provide: HTTP_INTERCEPTORS,
useClass: JwtInterceptor,
multi: true
};
ErrorInterceptorは、401があるかどうかを確認してから、localStorageからユーザーを削除してページをリロードします。
export class ErrorInterceptor implements HttpInterceptor {
constructor(private authenticationService: AuthService) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(request).pipe(catchError(err => {
if (err.status === 401) {
// auto logout if 401 response returned from api
this.authenticationService.logout();
location.reload(true);
}
const error = err.error.message || err.statusText;
return throwError(error);
}))
}
}
export const ErrorInterceptorProvider = { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }
また、ルートをアクティブ化する前にトークンがあることを確認するためのAuthGuardがあります。ログインページを除き、Angularルーターを構成するときにすべてのルートに含める必要があります。
export class AuthGuard implements CanActivate {
constructor(
private router: Router,
private authenticationService: AuthService
) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const currentUserToken = this.authenticationService.currentUserToken;
if (currentUserToken) {
return true;
}
// not logged in so redirect to login page with the return url
this.router.navigate(['/login'], { queryParams: { [ConstValue.ReturnUrl]: state.url }});
return false;
}
}
Userオブジェクトを使用する場合は、AuthService内でcurrentUserのパブリックオブザーバブルを取得します。たとえば、リストにユーザーユーザーの名を表示したい
export class AppComponent {
currentUser: User;
constructor(
private router: Router,
private authenticationService: AuthService
) {
this.authenticationService.currentUser.subscribe(
x => (this.currentUser = x)
);
}
logout() {
this.authenticationService.logout();
this.router.navigate(["/login"]);
}
}
そこからアイデアが浮かぶことを願っています。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加