【慧游鲁博】【8】前后端用户信息管理:用户基本信息在小程序端的持久化与随时获取
文章目录
- 本次更新
- 整体流程概述
- 1. 用户登录流程
- 前端登录处理 (`login.vue`)
- 后端登录处理 (`AuthServiceImpl.java`)
- 2. 用户信息存储机制
- 前端状态管理 (`member.js`)
- 3. 后续请求的身份验证
- 登录拦截器 (`LoginInterceptor.java`)
- 前端请求携带token
- 4. 获取用户信息
- 获取用户信息接口 (`UserController.java`)
- 前端获取和存储用户信息
- 安全设计考虑
- 综上所述
本次更新
在小程序端获取并保存当前用户的详细信息,支持后续对用户信息的使用。
整体流程概述
整个用户信息管理流程可以分为以下几个关键步骤:
- 用户登录:前端发送登录请求,后端验证并返回token
- 信息存储:前端存储token并获取用户详细信息
- 后续请求:每次请求携带token进行身份验证
- 信息获取:通过存储的token获取用户信息
下面我将详细分析每个环节的实现。
1. 用户登录流程
前端登录处理 (login.vue
)
在前端的handleLogin
方法中,主要完成了以下工作:
async handleLogin() {// 验证输入...// 发送登录请求const res = await post('/user/login', {username: this.loginForm.username,password: this.loginForm.password})// 存储tokenconst memberStore = useMemberStore()memberStore.setToken(res)uni.setStorageSync('token', res)// 获取用户详细信息并存储const userInfoRes = await get('/user/getUserInfo')memberStore.setUserInfo(userInfoRes)// 跳转逻辑...
}
- 前端发送登录请求到
/user/login
接口,携带用户名和密码 - 登录成功后,将返回的token存储到Pinia状态管理和uni-app的本地存储中
- 随后立即调用
/user/getUserInfo
获取用户详细信息并存储
后端登录处理 (AuthServiceImpl.java
)
后端登录逻辑主要位于AuthServiceImpl
类中:
public Result<String> login(UserLoginDTO loginDTO) {// 查询用户User user = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, loginDTO.getUsername()));// 验证用户存在性和密码if (user == null) return Result.fail(ErrorCode.USER_NOT_EXIST);if (!Md5Util.getMD5String(loginDTO.getPassword()).equals(user.getPassword())) {return Result.fail(ErrorCode.PASSWORD_ERROR);}// 生成JWT tokenMap<String, Object> claims = new HashMap<>();claims.put("id", user.getId());claims.put("username", user.getUsername());String token = JwtUtil.genToken(claims);// 将token存入RedisredisService.set(token, token, 1, TimeUnit.HOURS);return Result.success(token);
}
- 验证用户名和密码
- 生成包含用户ID和用户名的JWT token
- 将token存入Redis,设置1小时有效期
- 返回token给前端
2. 用户信息存储机制
前端状态管理 (member.js
)
前端使用Pinia进行状态管理,关键代码如下:
const profile = ref({token: '', // 登录令牌userInfo: null // 用户详细信息
})// 设置token
const setToken = (token) => {profile.value.token = token || ''
}// 设置用户信息
const setUserInfo = (userInfo) => {profile.value.userInfo = userInfo || null
}// 持久化配置
{persist: {storage: {getItem(key) {return uni.getStorageSync(key)},setItem(key, value) {uni.setStorageSync(key, value)},},}
}
- 使用
profile
对象存储token和用户信息 - 提供
setToken
和setUserInfo
方法更新状态 - 配置了持久化存储,将状态同步到uni-app的本地存储中
这种设计实现了:
- 内存中快速访问用户信息
- 页面刷新后仍能保持登录状态
- 统一的用户信息管理接口
3. 后续请求的身份验证
登录拦截器 (LoginInterceptor.java
)
后端通过拦截器验证每个请求的身份:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 从请求头获取tokenString token = request.getHeader("Authorization");try {// 从Redis验证token有效性String redisToken = operations.get(token);if (redisToken==null) throw new RuntimeException();// 解析token获取用户信息Map<String, Object> claims = JwtUtil.parseToken(token);// 存储到ThreadLocal中供后续使用ThreadLocalUtil.set(claims);return true;} catch (Exception e) {response.setStatus(401);return true;}
}
- 从
Authorization
请求头获取token - 检查Redis中是否存在该token(确保未过期)
- 解析token获取用户信息并存入ThreadLocal
- 验证失败返回401状态码
前端请求携带token
前端在member.js
中提供了获取token的方法:
// 获取token
const getToken = () => {return profile.value.token
}
在发起API请求时,前端应该从store中获取token并添加到请求头中:
const token = memberStore.getToken()
const res = await request({url: '/api/protected',headers: {'Authorization': token}
})
4. 获取用户信息
获取用户信息接口 (UserController.java
)
后端提供获取用户信息的接口:
@GetMapping("/getUserInfo")
public Result<UserVO> getUserInfo() {return userService.getUserInfo();
}
前端获取和存储用户信息
前端在登录成功后立即获取用户信息:
// 获取用户详细信息并存储
const userInfoRes = await get('/user/getUserInfo')
memberStore.setUserInfo(userInfoRes)
之后可以通过store随时获取(我亲爱的队友们,请你们关注这里):
const memberStore = useMemberStore()
const userInfo = memberStore.getUserInfo()
安全设计考虑
- Token有效期:后端设置token 1小时有效期(Redis中)
- 密码安全:后端存储密码的MD5哈希值而非明文
- 信息最小化:Token中只包含必要信息(id和username)
- HTTPS传输:虽然代码中未体现,但生产环境应使用HTTPS
综上所述
这套用户信息管理机制实现了:
- 安全的登录流程:验证用户名密码后生成有时效性的token
- 前后端状态同步:前端存储token和用户信息,后端验证每个请求
- 持久化存储:即使刷新页面也能保持登录状态
- 便捷的信息获取:通过store可以随时获取当前用户信息