在开发web应用时,不可避免地要用到鉴权机制。那么,什么是鉴权呢?鉴权就是在应用中或应用的某一部分中,对用户身份进行权限鉴定,只有符合权限要求的用户才可以访问相应的内容。
鉴权的设计思路是这样的:
- 在登录组件中,前端向后端提交数据,包括用户名和密码。
- 后端验证成功后,返回给前端一个
token
值,用来唯一标识该用户。 - 前端一般将这个token值存储在浏览器的
cookie
中,以备在鉴权时调用。当然存在session
中也是可以的,具体要看应用的需求了。 - 在路由配置中,给需要鉴权的模块添加路由守卫。
一个鉴权设计的例子
我们设计一个login
组件和一个auth
服务。其中auth服务颇为重要的。
这个auth
服务一般包含下面几个方法:
canActivate()
用来做路由守护。
login()
用来处理登录操作。
logout()
用来处理注销操作。
setToken()
用来设置token。
getToken()
用来获取token。
removeToken()
用来删除token。
完整的auth服务的代码如下所示:
import { Inject, Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { CanActivate, Router } from '@angular/router';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AuthService implements CanActivate {
private headers = new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
});
constructor(
@Inject('BASE_CONFIG') private config,
private http: HttpClient,
private router: Router
) { }
canActivate(): Observable<boolean> | boolean {
if (document.cookie.indexOf('token=') > -1) { // 如果能取到token,才可以跳转
return true;
} else {
this.router.navigate(['/login']); // 如果取不到token,跳转到登录页
return false;
}
}
login(data: any): Observable<any> {
const param = "userName=" + data.userName + "&password=" + data.password;
return this.http.post<any>('/labm/api/member/memberLogin', param, {headers: this.headers});
}
logout() {
this.removeToken();
this.router.navigate(['/']); // 跳转到登录页
}
setToken(t: string) {
document.cookie = `token=${t}`;
}
getToken() {
let token = '';
if (document.cookie) {
let arr_cookie = document.cookie.split(';');
let str_cookie_token = arr_cookie.filter(item => item.indexOf('token=') > -1);
token = str_cookie_token[0].split('=')[1]
} else {}
return token;
}
removeToken() {
document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
}
}
login组件的模板是这样的:
<form [formGroup]="form" (ngSubmit)="onSubmit(form, $event)">
<mat-card>
<mat-card-header>
<mat-card-title>
<mat-icon>vpn_key</mat-icon>
<span>欢迎登录</span>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<mat-form-field>
<input type="text" matInput placeholder="用户名" formControlName="userName">
<mat-error>请填写用户名</mat-error>
</mat-form-field>
<mat-form-field>
<input type="password" matInput placeholder="密码" formControlName="password">
<mat-error>请填写密码</mat-error>
</mat-form-field>
<div class="buttonGroup">
<a [routerLink]="[ '/']">取消</a>
<button mat-flat-button color="primary" type="submit" [disabled]="!form.valid">登录</button>
</div>
</mat-card-content>
</mat-card>
</form>
login组件的代码是这样的:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { AuthService } from 'src/app/services/auth.service';
@Component({
selector: 'yz-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
form: FormGroup;
constructor(
private fb: FormBuilder,
private auth$: AuthService,
private router: Router
) {
if (this.auth$.getToken()) { // 如果已经登录
this.router.navigate(['/user']);
} else {}
}
ngOnInit() {
this.form = this.fb.group({
userName: ['', Validators.required],
password: ['', Validators.required]
});
}
onSubmit({ value, valid }, ev: Event) {
ev.preventDefault();
if (valid) {
this.auth$.login(value).subscribe(r => {
if (r.success) {
this.auth$.removeToken();
this.auth$.setToken(r.data.token);
this.router.navigate(['/user']);
} else {
window.alert(r.message);
}
});
} else {}
}
}
注意一下,在login组件中要引入auth服务:

另外,在进行提交数据时,要先删除原有token值,然后再设置新值:

最后,在路由中给需要鉴权的模块添加路由守卫,比如给user模块添加:

网友评论