现在的网站中所有敏感操作都应要求用户经过身份验证(也就是说识别他们是谁)并获得授权(具有足够的权限来执行该操作)。如果 Web 路由无法检查用户身份,那么攻击者将能够访问敏感资源。
JavaScript 框架通常使用路由库来更新浏览器 URL 和页面内容以响应用户操作。在允许用户访问敏感路由之前,各位师傅们应该检查用户是否已通过身份验证,举例。
Angular 中的路由通常通过以下方式完成AppRoutingModule:
@NgModule({
imports: [RouterModule.forRoot([
// These paths are available to all users.
{ path: '', component: HomeComponent },
{ path: 'features', component: FeaturesComponent },
{ path: 'login', component: LoginComponent },
// These routes are only available to users after logging in.
{ path: 'feed', component: FeedComponent, canActivate: [ AuthGuard ]},
{ path: 'profile', component: ProfileComponent, canActivate: [ AuthGuard ]},
// This is the fall-through component when the route is not recognized.
{ path: '**', component: PageNotFoundComponent}
])],
exports: [RouterModule]
})
export class AppRoutingModule {}
React 中的路由通常使用react-router库完成
function Routes(props) {
return (
)
}
/**
* A wrapper for that redirects to the login screen if the user is not yet authenticated.
*/
function AuthenticatedRoute(props) {
if (props.loggedIn) {
return
}
return
}
但是,客户端的授权检查可能会被攻击者覆盖,因此在将数据加载到应用程序时检查用户是否登录非常重要。这些授权检查必须在服务器端代码中执行,并且客户端代码应该处理身份验证失败
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable {
// Check the user is logged in, redirect them to the login screen if they are not.
return this.authService.isLoggedIn().pipe(
map(isLoggedIn => {
if (!isLoggedIn) {
return this.router.parseUrl('/login')
}
return true
})
);
}
}
export class AuthService {
constructor(private http: HttpClient) {}
// Whether the user is currently logged in.
loggedIn: boolean | null = null
// The user object.
user: User | null = null
// Check whether the user is logged in.
isLoggedIn(): Observable {
return this.getCurrentUser().pipe(map(user => {
return user != null
}))
}
// Get the user definition from local state, or the server (if this is the first time we are checking).
getCurrentUser(): Observable {
if (this.loggedIn !== null) {
return of(this.user)
}
return this.http.get('/api/auth', {
responseType: 'json'
}).pipe(
tap({
next: user => {
// If we get a user definition from the server it indicates this user is logged in.
this.user = user
this.loggedIn = true
},
error: error => {
// A 401 response from the server indicates this user is not logged in.
this.user = null
this.loggedIn = false
}
}),
catchError(() => {
return of(null)
})
)
}
}
export interface User {
username: string;
}
class Feed extends React.Component {
constructor(props) {
super(props)
this.state = {
loading : true,
posts : [],
error : null
}
}
async componentDidMount() {
// Load the data for this component.
const response = await fetch('/api/feed')
const data = await response.json()
if (response.ok && data.success) {
// Set the data in the component state.
this.setState({
loading : false,
posts : data.posts
})
}
else {
// Shown an error message if the feed cannot be loaded - for instance,
// if the user is not authenticated.
this.setState({
loading : false,
error : data.error || 'There was a problem loading your feed.'
})
}
}
render() {
const error = this.state.error ? {this.state.error} : null
let body
if (this.state.loading) {
body = Loading...
}
else {
// Render the component based on the data returned from the server.
body = this.state.posts.map(post => {
return
})
}
return (
{error}
{body}
)
}
}
谢谢大佬的分享