登录访问控制
- AuthRoute 鉴权路由组件实现思路
- 参照官网自己封装AuthRoute 鉴权路由组件
- 实现修改登录成功后的跳转
概述
项目中的两种类型的功能和两种类型的页面:
两种功能:
- 登录后才能进行操作(比如:获取个人资料)
- 不需要登录就可以操作(比如:获取房屋列表)
两种页面:
- 需要登录才能访问(比如:个人中心页)
- 不需要登录即可访问(比如:首页)
对于需要登录才能操作的功能使用 axios 拦截器 进行处理(比如:统一添加请求头 authorization等)
对于需要登录才能访问的页面使用 路由控制
功能处理-使用axios拦截器统一处理token
- 在api.js 中,添加请求拦截器 (API.interceptors.request.user())
- 获取到当前请求的接口路径(url)
- 判断接口路径,是否是以/user 开头,并且不是登录或注册接口(只给需要的接口添加请求头)
- 如果是,就添加请求头Authorization
// 添加请求拦截器
API.interceptors.request.use(config => {
const { url } = config
// 判断请求url路径
if (
url.startsWith('/user') &&
!url.startsWith('/user/login') &&
!url.startsWith('/user/registered')
) {
// 添加请求头
config.headers.Authorization = getToken()
}
return config
})
- 添加响应拦截器 (API.interceptors.response.use())
- 判断返回值中的状态码
- 如果是400,标示token超时或异常,直接移除token
// 添加响应拦截器
API.interceptors.response.use(response => {
const { status } = response.data
if (status === 400) {
// 此时,说明 token 失效,直接移除 token 即可
removeToken()
}
return response
})
页面处理-AuthRoute鉴权路由组件
实现原理
-
限制某个页面只能在登陆的情况下访问,但是在React路由中并没有直接提供该组件,需要手动封装,来实现登陆访问控制(类似与Vue路由的导航守卫)
-
参数 react-router-dom的鉴权文档
-
AuthRoute 组件实际上就是对原来Route组件做了一次包装,来实现一些额外的功能
- 使用
-
render方法:render props模式,指定该路由要渲染的组件内容
-
Redirect组件:重定向组件,通过to属性,指定要跳转的路由信息
// 官网封装的核心逻辑代码
// ...rest 把之前的组件中传递的属性原封不动传递过来
function PrivateRoute({ component: Component, ...rest }) {
return (
<Route
{...rest}
// render方法: render props模式,指定该路由要渲染的组件内容
render={props =>
// 判断是否登陆,如果登陆,跳转配置的component,如果没有登陆,利用 Redirect组件来进行重定向
fakeAuth.isAuthenticated ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/login",
// 把当前的页面路径保存起来,方便用户登录后能够跳回当前页面
state: { from: props.location }
}}
/>
)
}
/>
);
}
封装AuthRoute鉴权路由组件
- 在components目录中创建AuthRoute/index.js 文件
- 创建组件AuthRoute并导出
- 在AuthRoute组件中返回Route组件(在Route基础上做了一层包装,用于实现自定义功能)
- 给Route组件,添加render方法,指定改组件要渲染的内容(类似与component属性)
- 在render方法中,调用isAuth() 判断是否登陆
- 如果登陆了,就渲染当前组件(通过参数component获取到要渲染的组件,需要重命名)
- 如果没有登陆,就重定向到登陆页面,并且指定登陆成功后腰跳转的页面路径
- 将AuthRoute组件接收到的props原样传递给Route组件(保证与Route组件使用方式相同)
- 使用AuthRoute组件配置路由规则,验证是否实现页面的登陆访问控制
const AuthRoute = ({ component: Component, ...rest }) => {
return (
<Route
{...rest}
render={props => {
const isLogin = isAuth()
if (isLogin) {
// 已登录
// 将 props 传递给组件,组件中才能获取到路由相关信息
return <Component {...props} />
} else {
// 未登录
return (
<Redirect
to={{
pathname: '/login',
state: {
from: props.location
}
}}
/>
)
}
}}
/>
)
}
export default AuthRoute
修改登录成功跳转
- 登陆成功后,判断是否需要跳转到用户想要访问的页面(判断props.location.state 是否有值)
- 如果不需要,则直接调用history.go(-1) 返回上一页
- 如果需要,就跳转到from.pathname 指定的页面(推荐使用replace方法模式,不是push)
// 表单的提交事件
handleSubmit: async (values, { props }) => {
...
if (status === 200) {
// 登录成功
localStorage.setItem('hkzf_token', body.token)
/*
1 登录成功后,判断是否需要跳转到用户想要访问的页面(判断 props.location.state 是否有值)。
2 如果不需要(没有值),则直接调用 history.go(-1) 返回上一页。
3 如果需要,就跳转到 from.pathname 指定的页面(推荐使用 replace 方法模式,而不是 push)。
*/
if (!props.location.state) {
// 此时,表示是直接进入到了该页面,直接调用 go(-1) 即可
props.history.go(-1)
} else {
// replace: [home, map]
props.history.replace(props.location.state.from.pathname)
}
} else {
// 登录失败
Toast.info(description, 2, null, false)
}
}