上一节我们有讲到如何对接登录接口的 【图文并茂】ant design pro 如何对接登录接口
仅仅能登录是最基本的,但是我们要进入后台还是需要另一个接口。
这个接口有两个作用:
- 来获取当前登录账号的信息,比如头像,用户名,还有一些权限信息等
- 来验证一下后台是否登录过
关于第二点,是很重要的,这个接口就是必须你要登录过一次,拿到 token 之后,才能访问到。
如果你没有 token ,也就是说没有登录过,这个接口访问的时候就会出问题,比如你都没登录过,你觉得能拿到个人信息吗,拿谁的。所以没有登录过的,就让它跳到登录页面,就是这个接口的作用。
有没有登录过,就只看浏览器有没有存好 token.
实现好后端
const getUserProfile = handleAsync(async (req: RequestCustom, res: Response) => {
// 确保在请求处理流程中间件中已经添加了解析 JWT 并设置 req.user
const user: IUser | null = await User.findById(req.user?._id)
.populate('roles') // 预加载 roles 字段
.exec();
if (user) {
// 再次预加载 permissions 字段,因为 roles 已经被预加载
await user.populate('roles.permissions');
res.json({
success: true,
data: {
...exclude(user.toObject(), 'password'),
avatar: 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png',
},
});
} else {
res.status(404);
throw new Error('User not found');
}
});
后端只是把 req.user 的信息拿到并返回给前端罢了。
比如这样的信息:
那么这个 req.user 是啥
我们看下路由
前面有个 protect 中间件,这个可以拿到 req.user
它的逻辑是这样的:
const protect = handleAsync(
async (req: RequestCustom, res: Response, next: NextFunction) => {
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith('Bearer')
) {
try {
token = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(
token,
process.env.JWT_SECRET as string,
) as jwt.JwtPayload;
const user: IUser | null = await User.findById(decoded.id)
.populate({
path: 'roles',
populate: {
path: 'permissions',
model: 'Permission',
},
})
.exec();
if (!user || !user.live) {
throw new Error('User is not live or not found');
}
req.user = user;
console.log('User is', user);
next();
} catch (error) {
console.error(error);
res
.status(401)
.send({ message: error.message || 'Not authorized, token failed' });
}
}
if (!token) {
res.status(401).send({ message: 'Not authorized, no token' });
}
},
);
主要是这里:
req.headers.authorization &&
req.headers.authorization.startsWith(‘Bearer’)
这个地方是从前端拿到头信息。
下一步就是通过 json web token 的库去解析这个字符串 token 。
token = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(
token,
process.env.JWT_SECRET as string,
) as jwt.JwtPayload;
拿到里面的 id 再去数据库把当前用户找出来,最后放到 req.user 中。
所以后面的 action 就可以拿到 req.user. 因为 protect 这里已经拿到并存到 req 了。
如果找不到
if (!token) {
res.status(401).send({ message: 'Not authorized, no token' });
}
就会给前端一个 401 状态码。前端拿到 401 状态码,就会跳出到登录页面。
process.env.JWT_SECRET 上面有个密钥,这是服务器存的,不能暴露出去,就像你家的钥匙一样。
所以我们这个 token 是安全,就算别人伪造了信息,他没有你的 key ,后面也是解析不了,能判断是不是假的数据。
其实最上面 getUserProfile 里的
const user: IUser | null = await User.findById(req.user?._id)
.populate(‘roles’) // 预加载 roles 字段
.exec();
并不是必要的,因为 req.user 应该有 user 的对象记录信息了。当然再查一遍也是没问题。
前端实现
主要是还是在这里:
src/app.tsx
export async function getInitialState(): Promise<{
settings?: Partial<LayoutSettings>;
currentUser?: API.CurrentUser;
loading?: boolean;
fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
}> {
const fetchUserInfo = async () => {
try {
const response = await queryCurrentUser({
skipErrorHandler: true,
});
return response.data;
} catch (error) {
history.push(loginPath);
}
return undefined;
};
// 如果不是登录页面,执行
const { location } = history;
if (location.pathname !== loginPath) {
const currentUser = await fetchUserInfo();
return {
fetchUserInfo,
currentUser,
settings: defaultSettings as Partial<LayoutSettings>,
};
}
return {
fetchUserInfo,
settings: defaultSettings as Partial<LayoutSettings>,
};
}
还是跟以前一样,要对接好请求地址,方法,参数
queryCurrentUser
这个逻辑是这样的:
export async function currentUser(options?: { [key: string]: any }) {
return request<API.CurrentUser>('/auth/profile', {
method: 'GET',
...(options || {}),
});
}
用的是 get 方法,地址要对。
后面是这个
const response = await queryCurrentUser({
skipErrorHandler: true,
});
return response.data;
响应的数据要对上
跟这里的数据结构是要对上的API.CurrentUser
type CurrentUser = {
isAdmin: CurrentUser | undefined;
data?: any;
name?: string;
avatar?: string;
role?: string;
roles?: any;
_id?: string;
userid?: string;
email?: string;
signature?: string;
title?: string;
group?: string;
tags?: { key?: string; label?: string }[];
notifyCount?: number;
unreadCount?: number;
country?: string;
access?: string;
geographic?: {
province?: { label?: string; key?: string };
city?: { label?: string; key?: string };
};
address?: string;
phone?: string;
};
也就是这里的
这里可能还差一个东西,我们要把 token 提交过去。
我们下一节来讲
- ant design pro 如何去保存颜色
- ant design pro v6 如何做好角色管理
- ant design 的 tree 如何作为角色中的权限选择之一
- ant design 的 tree 如何作为角色中的权限选择之二
- ant design pro access.ts 是如何控制多角色的权限的
- ant design pro 中用户的表单如何控制多个角色
- ant design pro 如何实现动态菜单带上 icon 的
- ant design pro 的表分层级如何处理
- ant design pro 如何处理权限管理
- ant design pro 技巧之自制复制到剪贴板组件
- ant design pro 技巧之实现列表页多标签
- 【图文并茂】ant design pro 如何对接登录接口