Я пытаюсь найти / создать правильный (лучший) способ получения и использования пользовательских утверждений в приложении Angular. Я добавил заявление администратора через облачную функцию. То, что я хочу иметь (и то, что я пытался сделать до этого) сейчас:
- Получить заявки (и зарегистрированного пользователя) в одной службе (например,
auth.service
) - Разрешить всем другим компонентам, которым необходимо прочитать утверждения, сделать это через простой API из этой службы.
- Не разрешать другим компонентам подписываться на authState или что-либо еще (просто прочитайте синхронно атрибуты моего
auth.service
)
Зачем мне это нужно? - потому что я считаю, что он более читабелен и его легче поддерживать
(только читая (подписываясь на) authState
в одном месте (например, authService.ts
), что упрощает обслуживание и позволяет другим компонентам синхронно читать утверждения из authService.ts
атрибутов / полей)
Итак, код для того, что я я делаю сейчас (который не работает ... см. POINTS_IN_CODE ):
auth.service.ts
// imports omitted for brevity...
@Injectable()
export class AuthService {
user: Observable<User> = of(null);
uid: string;
claims: any = {};
claimsSubject = new BehaviorSubject(0);
constructor(private afAuth: AngularFireAuth,
private afStore: AngularFirestore,
private functions: AngularFireFunctions) {
this.afAuth.authState
.subscribe(
async authUser => {
if (authUser) { // logged in
console.log(`Auth Service says: ${authUser.displayName} is logged in.`);
this.uid = authUser.uid;
this.claims = (await authUser.getIdTokenResult()).claims;
// POINT_IN_CODE_#1
this.claimsSubject.next(1);
const userDocumentRef = this.afStore.doc<User>(`users/${authUser.uid}`);
// if provider is Google (or Facebook <later> (OR any other 3rd party))
// document doesn't exist on the first login and needs to be created
if (authUser.providerData[0].providerId === 'google.com') {
userDocumentRef.get()
.subscribe( async snapshot => {
if ( ! snapshot.exists) { // if the document does not exist
console.log(`\nNew document being created for: ${authUser.displayName}...`); // create a user document
await userDocumentRef.set({name: authUser.displayName, email: authUser.email, provider: 'google.com'});
}
});
}
this.user = userDocumentRef.valueChanges();
}
else { // logged out
console.log('Auth Service says: no User is logged in.');
}
}
);
}
login(email, password): Promise<any> {
return this.afAuth.auth.signInWithEmailAndPassword(email, password);
}
hasClaim(claim): boolean {
return this.hasAnyClaim([claim]);
}
hasAnyClaim(paramClaims): boolean {
for (let paramClaim of paramClaims) {
if (this.claims[paramClaim]) {
return true;
}
}
return false;
}
}
login.component.ts
// imports...
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
form: FormGroup;
hide = true;
errorMessage = '';
loading = false;
constructor(private fb: FormBuilder,
public authService: AuthService,
private router: Router) {}
ngOnInit() {
this.logout();
this.form = this.fb.group({
username: ['test@test.te', Validators.compose([Validators.required, Validators.email])],
password: ['Asdqwe123', Validators.compose([Validators.required])]
});
}
submit() {
this.loading = true;
this.authService.login(this.form.value.username, this.form.value.password)
.then(resp => {
this.loading = false;
// POINT_IN_CODE_#2
// what I am doing right now, and what doesn't work...
this.authService.user
.subscribe(
resp => {
if (this.authService.hasClaim('admin')) {
this.router.navigate(['/admin']);
}
else {
this.router.navigate(['/items']);
}
}
);
// POINT_IN_CODE_#3
//this.authService.claimsSubject
// .subscribe(
// num => {
// if (num === 1) {
// if (this.authService.hasClaim('admin')) {
// this.router.navigate(['/admin']);
// }
// else {
// this.router.navigate(['/items']);
// }
// }
// });
}
logout() {
this.authService.logout();
}
}
POINTS_IN_CODE
В auth.service.ts
в POINT_IN_CODE_#1
- у меня была идея выбросить из этого су bject claimsSubject
и в login.component.ts
на POINT_IN_CODE_#3
подпишитесь на него и знайте, что, если оно имеет значение 1
, заявки были получены в auth.service.ts
из authState
.
В login.component.ts
в POINT_IN_CODE_#2
я знаю, что могу получить претензии от resp.getIdTokenResult
, но он просто не "чувствует" правильно ... о чем этот вопрос, в основном. ..
Конкретный вопрос, который я мог бы задать, заключается в следующем:
Я хочу иметь возможность перенаправить пользователя после входа на страницу admin
, если у него есть пользовательские претензии 'admin' .
Я хотел бы сделать это, как я уже говорил выше (если это возможно, И если это хорошо / улучшая читаемость / улучшая_основность), без , подписавшихся на authState
напрямую, но через некоторую «вещь» из auth.service.ts
.
Я бы использовал тот же «logi c», чтобы сделать, например, AuthGuard
, который бы просто вызывал authService.hasClaim('admin')
, и не должен был бы подписаться на authState
самому, чтобы сделать проверку.
NB Я хочу знать, хорошо ли, как я это сделал, если есть какие-либо cavea тс или просто простые улучшения. Все предложения и комментарии приветствуются, поэтому, пожалуйста, оставляйте комментарии, особенно на мой Зачем мне это нужно? part!
Edit-1: Добавлена подсветка машинописного кода и указано точное место в моем коде, которое не работает так, как я хочу.
Edit-2: Отредактировал некоторые комментарии относительно причин, по которым мой authService .user был нулевым ... (У меня был какой-то прогон кода, который установил его на ноль, прежде чем он был проверен в компоненте входа ...)