antd pro4-(2)登录相关调整

antd pro默认访问后,直接进入主界面的欢迎。
我需要改变一下方式,所有用户需要登录后才可以访问主界面,还有配合后端返回的数据格式,以及使用token来判断是否登录。

大致思路:

  • 登录成功后将token放入localStorage
  • 退出登录的时候清除token
  • Request拦截器:发送请求时,从localStorage获取token加入请求头中
  • Request拦截器:接收返回时,统一处理错误
  • SecurityLayout中,通过校验token来判断是否需要登录

冲冲冲…

更改mock数据~~/mock/user.js
后端返回的数据格式为

{
	code: {},
	msg: {},
	data: {},
}

因为和PRO自带的mock数据不太符合,先调整下方便测试。
登录发起请求是/api/login/account,调整下:

  'POST /api/login/account': (req, res) => {
    const { password, userName, type } = req.body;
    if (password === 'ant.design' && userName === 'admin') {
      res.send(
        {
          code: 1,
          msg: '',
          data: {
            token: 'admin.token.2ijfhjf.jwijeiwfj.sjidjifs',
            currentAuthority: 'admin',
            type
          },
        }
      );
      return;
    }

    if (password === 'ant.design' && userName === 'user') {
      res.send(
        {
          code: 1,
          msg: '',
          data: {
            token: 'user.token.2ijfhjf.jwijeiwfj.sjidjifs',
            currentAuthority: 'user',
            type
          },
        }
      );
      return;
    }
    res.send({
      code: 500,
      msg: '用户名或密码错误',
      data: {
        token: '',
        currentAuthority: 'guest',
        type
      },
    });
  },

token是后端用JWT生成
currentAuthority是就是用户所有角色,antd pro支持如‘admin’和[‘admin’,‘user’]
type是前端发起请求,从界面组件带过去参数,用来识别是登录方式,原本的mock数据把type又返回回去,暂时没研究后续有什么用处

将token放入localStorage~~/models/login.js:
变更下reducers,将token放入localStorage.
原本登录成功后,setAuthority会把用户的角色权限放入localStorage中,这里因为不打算在config中设置权限,改为通过后端校验,所以暂时先注释掉。

reducers: {
    changeLoginStatus(state, { payload }) {
+      localStorage.setItem('user-token', payload.data.token);
-      //setAuthority(payload.data.currentAuthority);
      return { ...state, status: payload.code, type: payload.data.type };
    },
  },

退出登录的时候清除token~~/models/login.js:

	logout() {
      const { redirect } = getPageQuery(); // Note: There may be security issues, please note

      if (window.location.pathname !== '/user/login' && !redirect) {
+        localStorage.removeItem('user-token');
        router.replace({
          pathname: '/user/login',
          search: stringify({
            redirect: window.location.href,
          }),
        });
      }
    },

Request拦截器~~/utils/request.js:

参考 官方request

前端在pro中打算统一通过Request发起请求,(后端对每个请求都需要识别和校验用户权限),添加拦截器把token加入请求头。

前端收到后端响应后,统一处理异常对后续开发相对方便。
默认代码里有提供errorHandler用来处理异常,
但后端响应请求的时候,比如权限不足等,我并没有返回相应的状态码。
直接返回相应状态码然后使用errorHandler来处理会更好,这里暂不考虑。
所以通过拦截器,解析响应对象来统一处理异常。
代码以后再优化:

//发送请求前,header加入token
request.interceptors.request.use(async (url, options) => {
  const token = localStorage.getItem("user-token");
  console.log("request-put header token: "+token);
  const headers = {
    'Content-Type': 'application/json',
  };

  if (token) {
    headers['token'] = token;
  }
  return (
    {
      url: url,
      options: { ...options, headers: headers },
    }
  );
})

//返回后的特殊处理 克隆响应对象做解析处理
request.interceptors.response.use(async (response) => {
  const data = await response.clone().json();
  console.log("request-json-data: " + JSON.stringify(data));
  if(data.code){
    //需要登录
    if(data.code === 0){
      window.g_app._store.dispatch({
        type: 'login/logout',
      });
      notification.error({
        message: '未登录或登录已过期,请重新登录。',
      });
      return;
    }
    if (data.code === 403) {
      //router.push('/exception/403');
      //return;
      notification.error({
        message: '权限不足,请联系管理员。',
      });
    }
    if (data.code === 500) {
      notification.error({
        message: data.msg,
      });
    }
  }

  return response;
});

修改SecurityLayout
使用token来判断是否已登录

render() {
    const { isReady } = this.state;
    const { children, loading } = this.props;
    // 你可以把它替换成你自己的登录认证规则(比如判断 token 是否存在)
-    // const { currentUser } = this.props;
-    //const isLogin = currentUser && currentUser.userid;
+    const isLogin = localStorage.getItem("user-token");

    const queryString = stringify({
      redirect: window.location.href,
    });

    if ((!isLogin && loading) || !isReady) {
      return <PageLoading />;
    }

    if (!isLogin) {
      return <Redirect to={`/user/login?${queryString}`}></Redirect>;
    }

    return children;
  }

需要登录后才进入欢迎界面的效果,去掉发送Action-fetchCurrent。在BasicLayout中,初始化也会fetchCurrent来获取用户信息,SecurityLayout里的这段猜测是方便演示用的吧(看代码的时候被这两个Layout都去fetchCurrent搞得我很晕,到现在都满是不确定性,注释掉后感觉很舒服)。

  componentDidMount() {
    this.setState({
      isReady: true,
    });
    /*
    const { dispatch } = this.props;
    if (dispatch) {
      dispatch({
        type: 'user/fetchCurrent',
      });
    }
     */
  }

因为没用到user的model,先注释掉了。原本的是{ loading , user }

export default connect(({ loading }) => ({
  //currentUser: user.currentUser,
  loading: loading.models.user,
}))(SecurityLayout);

清掉浏览器缓存测试下
访问不再直接进主页了,需要登录;
用user登录,尝试访问下admin权限的http://localhost:8000/admin,跳出403页面;

这是BasicLayout原本的实现,组件Authorized中也有类似实现。

const noMatch = (
  <Result
    status="403"
    title="403"
    subTitle="Sorry, you are not authorized to access this page."
    extra={
      <Button type="primary">
        <Link to="/user/login">Go Login</Link>
      </Button>
    }
  />
);

退出登录,输入个错的用户名,弹出“用户名或密码错误”的消息;
换admin登录,看到admin权限的管理页;
妥,暂时没发现什么问题。
还有登录页不需要手机登录/忘记密码/其他登录/注册用户等再慢慢调了。
先到这,后续再来实现权限及菜单。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值