我正在按一定角度实施AdmingGuard,以保护某些路线。
管理员警卫:
// --------------ADMIN GUARD
// want protect routes from user who are not Admin
canActivate(): boolean {
// isLogged() service method: set 2 global boolean variable in teh service:
//- 'isLogged'= true if the user is logged in
//- 'adminLoggedIn' = true if the logged user is an Admin
this.authService.isLogged();
// getIsAdminLogged() service method: return value of global var 'adminLoggedIn'
const adminLoggedIn = this.authService.getIsAdminLogged();
if (adminLoggedIn) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
服务:
// SERVICE
//here global variable:
loggedIn: boolean; // the user is logged ?
adminLoggedIn: boolean; // the logged user is an Admin ?
constructor(private http: HttpClient, private router: Router) {}
// this makes an Http Request to the server sending the AccessToken
// and control if the user that sent the AccesToken is logged and if is an Admin
isLogged() {
// get the AccessToken from localStorage, if is empty: im sure the user is not logged
const accessToken = this.getAccessToken;
if (typeof accessToken === 'undefined' || accessToken === null) {
this.loggedIn = false;
this.adminLoggedIn = false;
return;
}
// here makes the https ruquest to the server
return this.http
.get<any>(this.isLoggedUrl)
.pipe(catchError(this.errorHandler))
.subscribe(
(res) => {
// server send back the 'res' response
// control in the 'res' if the user is logged and if the user is an Admin
// in base on this controls, set the 2 global var 'loggedIn' and 'adminLoggedIn'
if (res.status == 200) {
this.loggedIn = true;
if (res.userType == 'admin') {
this.adminLoggedIn = true;
}
} else {
this.adminLoggedIn = false;
}
},
(err) => {
// server sand back some error
// control if the error is 'TokenExpiredError' (in that case try to refresh the tokens)
// otherwise set the 2 vars 'loggedIn' and 'adminLoggedIn' to false
if (err.error.message == 'TokenExpiredError') {
const refreshToken = this.getRefreshToken;
if (typeof refreshToken === 'undefined' || refreshToken === null) {
this.loggedIn = false;
this.adminLoggedIn = false;
} else {
// refresh tokens if possible
// also this method set the var 'loggedIn' and 'adminLoggedIn'
this.refreshTokens();
}
} else {
this.loggedIn = false;
this.adminLoggedIn = false;
}
}
);
}
// return the value of the global var 'adminLoggedIn'.
getIsAdminLogged() {
return this.adminLoggedIn;
}
问题所在
按照CanActivate中语句的顺序,它应该执行:
但是HTTP请求没有异步,所以getIsAdminLogged();在验证该HTTP请求之前是否已执行该用户。
我已经阅读了一些解决方案,但我仍然感到困惑。
THX
答案 0 :(得分:0)
盲目更改所有代码,告诉我是否有问题
管理员防护
async canActivate(): boolean {
this.authService.tokenValid()
let that = this
await this.authService.isLogged().then(res => {
if (res.status == 200) {
that.authService.setStatusUser(true)
if (res.userType == 'admin') {
that.authService.setStatusUser(true)
}
} else {
that.authService.setStatusAdmin(false)
}
}).catch(err => {
if (err.error.message == 'TokenExpiredError') {
that.authService.setRefresh()
} else {
that.authService.setError()
}
});
// getIsAdminLogged() service method: return value of global var 'adminLoggedIn'
const adminLoggedIn = this.authService.getIsAdminLogged();
if (adminLoggedIn) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
服务
import 'rxjs/add/operator/toPromise';
...some code ...
setStatusAdmin(status: boolean){
this.adminLoggedIn = status;
}
setStatusUser(status: boolean){
this.loggedIn = status
}
setError(){
this.loggedIn = false;
this.adminLoggedIn = false;
}
setRefresh(){
const refreshToken = this.getRefreshToken;
if (typeof refreshToken === 'undefined' || refreshToken === null) {
this.loggedIn = false;
this.adminLoggedIn = false;
} else {
// refresh tokens if possible
// also this method set the var 'loggedIn' and 'adminLoggedIn'
this.refreshTokens();
}
}
tokenValid(){
const accessToken = this.getAccessToken;
if (typeof accessToken === 'undefined' || accessToken === null) {
this.loggedIn = false;
this.adminLoggedIn = false;
}
}
isLogged(): Promise<any> {
return this.http
.get<any>(this.isLoggedUrl)
.pipe(catchError(this.errorHandler)).toPromise()
}
答案 1 :(得分:0)
loggedIn: boolean;
而不是布尔值,将其设置为“ null”
loggedIn:null
保护文件this.authService.getIsAdminLogged()
中的将返回可观察的。警卫队将等到可观察到的“完成”状态。在管理员防护文件中,返回以下内容:
import { take, skipWhile, tap } from 'rxjs/operators';
//http service returns observable
return this.authService.getIsAdminLogged().pipe(
skipWhile((value) => value === null),
// if the value is null, we are not getting any value, we are getting either false or true and faking that this observable is complete
// before u were getting false by default. the issue was while app component checking for authentication, guard would consider that it was false, maybe 1 second later it gets the answe as true
// to prevent this issue we are giving the final result to the guard
take(1),
//tap() does not modify the incoming value
tap((authenticated) => {
if (!authenticated) {
this.router.navigateByUrl('/');
}
})
);