功能分析
判断是否登录(本地缓存中是否有token信息,直接调用isAuth() 方法即可,这里在utils/auth.js文件中已经封装好了)
如果登录了,就发送请求获取个人资料,并且在页面中展示个人资料
如果没有登录,则不获取个人资料,只在页面中展示未登录信息
在页面中展示登录或未登录信息,就要通过state变化来体现,因此,需要一个标示是否登录的状态
//判断用户是否登陆步骤 //在state中添加两个状态:isLogin(是否登录)和userInfo(用户信息) state = { // 是否登录 isLogin: isAuth(), // 用户信息 userInfo: { avatar: '', nickname: '' } } //创建方法getUserInfo,用户来获取个人资料 async getUserInfo() { ... } 在方法中,通过isLogin判断用户是否登录 if (!this.state.isLogin) { // 未登录 return }
如果没有登录,则不发送请求,渲染未登录信息 // 对用结构使用状态来判断显示登录还是未登录UI {/* 登录后展示: */} {isLogin ? ( <> <div className={styles.auth}> <span onClick={this.logout}>退出</span> </div> <div className={styles.edit}> 编辑个人资料 <span className={styles.arrow}> <i className="iconfont icon-arrow" /> </span> </div> </> ) : ( <div className={styles.edit}> <Button type="primary" size="small" inline onClick={() => history.push('/login')} > 去登录 </Button> </div> )}
如果已登录,就根据接口发送请求,获取用户个人资料
渲染个人资料数据
async getUserInfo() { if (!this.state.isLogin) { // 未登录 return } // 发送请求,获取个人资料 const res = await API.get('/user', { headers: { authorization: getToken() } }) if (res.data.status === 200) { // 请求成功 const { avatar, nickname } = res.data.body this.setState({ userInfo: { avatar: BASE_URL + avatar, nickname } }) } } // render方法中 render(){ const { history } = this.props const { isLogin, userInfo: { avatar, nickname } } = this.state return ( <div className={styles.root}> {/* 个人信息 */} <div className={styles.title}> <img className={styles.bg} src={BASE_URL + '/img/profile/bg.png'} alt="背景图" /> <div className={styles.info}> <div className={styles.myIcon}> <img className={styles.avatar} src={avatar || DEFAULT_AVATAR} alt="icon" /> </div> <div className={styles.user}> <div className={styles.name}>{nickname || '游客'}</div> ... }
退出功能 点击退出按钮,弹出对话框,提示是否确定退出 给退出按钮绑定点击事件,创建方法logout作为事件处理函数 在退出按钮的事件处理程序中,先调用退出接口(让服务器端退出),再移除本地token(本地退出) 把登录状态isLogin设置为false,清空用户状态对象
{ text: '退出', onPress: async () => { // 调用退出接口 await API.post('/user/logout', null, { headers: { authorization: getToken() } }) // 移除本地token removeToken() // 处理状态 this.setState({ isLogin: false, userInfo: { avatar: '', nickname: '' } }) } }
登录访问控制 目标 理解访问控制中的两种功能和两种页面 能够说出处理两种功能用什么方式来实现 能够写出 axios请求拦截器与响应拦截器,并且能够说出这两种拦截器分别在什么时候触发,有什么作用 能够说出处理两种页面用什么方式来实现 能够说出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鉴权路由组件
封装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 }) => { console.log('rest', rest) return ( <Route {...rest} render={props => { const isLogin = isAuth() if (isLogin) { // 已登录 // 将 props 传递给组件,组件中才能获取到路由相关信息 return <Component {...props} /> } else { // 未登录 return ( <Redirect to={{ pathname: '/login', state: { backUrl: 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) } }
本文参考自:https://blog.csdn.net/weixin_45583708/article/details/103327917