![image-20230225060710
前面我们完成了用户登录、用户认证与就诊人管理,现在我们需要把这些信息在我们的平台管理系统中进行统一管理
简单的设置redis和cookie的过期时间,会导致用户在操作的过程中掉线,为了解决这个问题,我们可以使用token续期的方案,具体的做法是生成一个刷新token。
设置token与refreshToken
,都包含用户信息(userId、name、headimgurl),可以一样可以不一样,refreshToken比token时间更长,如token30分钟,refreshToken60分钟
在ApiWxController的callback方法的return "redirect:"
前面,将之前的生成token和存储token的相关代码封装到saveToken方法中。
将如下代码进行封装:
封装成如下代码:
@Resource
private AuthContextHolder authContextHolder;
UserVo userVo = new UserVo();
userVo.setName(name);
userVo.setUserId(userInfo.getId());
userVo.setHeadimgurl(userInfo.getHeadImgUrl());
authContextHolder.saveToken(userVo, response);
return "redirect:" + constantProperties.getSytBaseUrl();
service-util中引入依赖
<!--实体-->
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>model</artifactId>
<version>1.0</version>
</dependency>
在AuthContextHolder中添加如下方法:
/**
* 将token和refreshToken保存在redis和cookie中的通用方法
* @param userVo
* @param response
*/
public void saveToken(UserVo userVo, HttpServletResponse response) {
int redisMaxTime = 30;
//生成token/refreshToken
String token = getToken();
String refreshToken = getToken();
//将生成token/refreshToken存入redis:token做键,userVo做值
redisTemplate.opsForValue()//30分钟
.set("user:token:" + token, userVo, redisMaxTime, TimeUnit.MINUTES);
redisTemplate.opsForValue()//60分钟
.set("user:refreshToken:" + refreshToken, userVo, redisMaxTime * 2, TimeUnit.MINUTES);
//将token、refreshToken和name存入cookie
int cookieMaxTime = 60 * 30;//30分钟
CookieUtils.setCookie(response, "token", token, cookieMaxTime);
CookieUtils.setCookie(response, "refreshToken", refreshToken, cookieMaxTime * 2);
CookieUtils.setCookie(response, "name", URLEncoder.encode(userVo.getName()), cookieMaxTime * 2);
CookieUtils.setCookie(response, "headimgurl", URLEncoder.encode(userVo.getHeadimgurl()), cookieMaxTime * 2);
}
private String getToken(){
return UUID.randomUUID().toString().replaceAll("-", "");
}
修改checkAuth方法,当token不存在时,续期token
/**
* 检查授权状态并续期
* @param request
* @return
*/
public Long checkAuth(HttpServletRequest request, HttpServletResponse response){
//从http请求头中获取token
String token = request.getHeader("token");
if(StringUtils.isEmpty(token)) {
//throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
return refreshToken(request, response);//刷新token
}
Object userVoObj = redisTemplate.opsForValue().get("user:token:" + token);
if(userVoObj == null){
//throw new GuiguException(ResultCodeEnum.LOGIN_AUTH);
return refreshToken(request, response);//刷新token
}
UserVo userVo = (UserVo)userVoObj;
return userVo.getUserId();
}
/**
* 刷新token
* @param request
* @param response
* @return
*/
public Long refreshToken(HttpServletRequest request, HttpServletResponse response) {
//从cookie中获取刷新token
String refreshToken = CookieUtils.getCookie(request, "refreshToken");
//从redis中根据刷新token获取用户信息
Object userVoObj = redisTemplate.opsForValue().get("user:refreshToken:" + refreshToken);
if(userVoObj == null) {
//LOGIN_AURH(214, "登录过期"),
throw new GuiguException(ResultCodeEnum.LOGIN_TIMEOUT);//登录过期
}
UserVo userVo = (UserVo) userVoObj;
saveToken(userVo, response);
return userVo.getUserId();
}
FrontUserInfoController和FrontFileController中的方法,添加response参数
跨域ajax访问时,session_id不会被存储,cookie不会被传递到后端,因此需要解决cookie跨域存储的问题
解决方案:
(1)网关配置文件CorsConfig中添加如下设置:
config.setAllowCredentials(true); //避免跨域访问时session_id每次不一致
(2)前端axios初始化文件request.js添加如下设置:
withCredentials: true //避免跨域访问时session_id每次不一致
如果接口返回214状态(登录超时),说明用户超时未操作,直接退出。
// http response 拦截器
service.interceptors.response.use(
response => {
//如果响应码是214,则需要登录超时
if (response.data.code === 214) {
// to re-login
MessageBox.confirm('登录超时, 请重新登录', '确认退出', {
confirmButtonText: '重新登录',
cancelButtonText: '回到首页',
type: 'warning'
}).then(() => {
window.location.href = process.env.BASE_API + '/front/user/wx/login'
}).catch(()=>{
window.location.href = '/'
})
}else if (response.data.code !== 200) {
Message({
message: response.data.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(response.data)
} else {
return response.data
}
},
error => {
return Promise.reject(error.response)
})
myheader.vue中showInfo方法的修改,保证token过期后,用户名信息依然显示
showInfo() {
let refreshToken = cookie.get('refreshToken')
if (refreshToken) {
this.name = cookie.get('name')
this.headimgurl = cookie.get('headimgurl')
}
},
myheader.vue中退出登录方法的修改,需要清空refreshToken
cookie.set('name', '', {domain: 'localhost'})
cookie.set('token', '', {domain: 'localhost'})
cookie.set('refreshToken', '', {domain: 'localhost'}) //清空refreshToken
cookie.set('headimgurl', '', {domain: 'localhost'})
补充:由于我们解决了cookie的ajax传递跨域问题,因此之前通过header传输的token其实可以不必要了,我们可以直接在后端从cookie中获取token的值,如下:
String token = request.getHeader("token");
//以上可以替换为如下:
String token = CookieUtils.getCookie(request, "token");
FrontPatientController:
package com.atguigu.syt.user.controller.front;
@Api(tags = "就诊人管理")
@RestController
@RequestMapping("/front/user/patient")
public class FrontPatientController {
@Resource
private PatientService patientService;
@Resource
private AuthContextHolder authContextHolder;
@ApiOperation("添加就诊人")
@ApiImplicitParam(name = "patient",value = "就诊人对象", required = true)
@PostMapping("/auth/save")
public Result savePatient(@RequestBody Patient patient, HttpServletRequest request, HttpServletResponse response) {
Long userId = authContextHolder.checkAuth(request, response);
patient.setUserId(userId);
patientService.save(patient);
return Result.ok().message("保存成功");
}
}
FrontPatientController:
@ApiOperation("修改就诊人")
@ApiImplicitParam(name = "patient",value = "就诊人对象", required = true)
@PutMapping("/auth/update")
public Result updatePatient(@RequestBody Patient patient, HttpServletRequest request, HttpServletResponse response) {
authContextHolder.checkAuth(request, response);
patientService.updateById(patient);
return Result.ok().message("修改成功");
}
FrontPatientController:
@ApiOperation("根据id获取就诊人信息")
@ApiImplicitParam(name = "id",value = "就诊人id", required = true)
@GetMapping("/auth/get/{id}")
public Result<Patient> getPatient(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) {
Long userId = authContextHolder.checkAuth(request, response);
//加上userId参数,只可以获取自己名下的就诊人信息
Patient patient = patientService.getPatientById(id, userId);
return Result.ok(patient);
}
接口:PatientService
/**
* 根据id获取本人名下的就诊人信息
* @param id
* @param userId
* @return
*/
Patient getPatientById(Long id, Long userId);
实现:PatientServiceImpl
@Override
public Patient getPatientById(Long id, Long userId) {
LambdaQueryWrapper<Patient> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Patient::getUserId, userId).eq(Patient::getId, id);
Patient patient = baseMapper.selectOne(queryWrapper);
//封装数据
return this.packPatient(patient);
}
辅助方法
@Resource
private DictFeignClient dictFeignClient;
@Resource
private RegionFeignClient regionFeignClient;
/**
* 封装Patient对象里面其他参数
* @param patient
* @return
*/
private Patient packPatient(Patient patient) {
String certificatesTypeString = dictFeignClient.getName(DictTypeEnum.CERTIFICATES_TYPE.getDictTypeId(),patient.getCertificatesType());
String contactsCertificatesTypeString = dictFeignClient.getName(
DictTypeEnum.CERTIFICATES_TYPE.getDictTypeId(),patient.getContactsCertificatesType());
String provinceString = regionFeignClient.getName(patient.getProvinceCode());
String cityString = regionFeignClient.getName(patient.getCityCode());
String districtString = regionFeignClient.getName(patient.getDistrictCode());
patient.getParam().put("certificatesTypeString", certificatesTypeString);
patient.getParam().put("contactsCertificatesTypeString", contactsCertificatesTypeString);
patient.getParam().put("provinceString", provinceString);
patient.getParam().put("cityString", cityString);
patient.getParam().put("districtString", districtString);
patient.getParam().put("fullAddress",
provinceString + cityString + districtString + patient.getAddress());
return patient;
}
FrontPatientController
@ApiOperation("获取就诊人列表")
@GetMapping("/auth/findAll")
public Result<List<Patient>> findAll(HttpServletRequest request, HttpServletResponse response) {
Long userId = authContextHolder.checkAuth(request, response);
List<Patient> list = patientService.findByUserId(userId);
return Result.ok(list);
}
接口:PatientService
/**
* 根据userId获取就诊人列表
* @param userId
* @return
*/
List<Patient> findByUserId(Long userId);
实现:PatientServiceImpl
@Override
public List<Patient> findByUserId(Long userId) {
LambdaQueryWrapper<Patient> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Patient::getUserId, userId);
List<Patient> patientList = baseMapper.selectList(queryWrapper);
patientList.forEach(patient -> {
patient.getParam().put("expenseMethod", patient.getIsInsure()==0?"自费":"医保");
});
return patientList;
}
FrontPatientController:
@ApiOperation("删除就诊人")
@DeleteMapping("/auth/remove/{id}")
public Result removePatient(@PathVariable Long id, HttpServletRequest request, HttpServletResponse response) {
Long userId = authContextHolder.checkAuth(request, response);
//加上userId参数,只可以删除自己名下的就诊人信息
patientService.removeById(id, userId);
return Result.ok();
}
接口:PatientService
/**
* 根据id删除自己名下的就诊人信息
* @param id
* @param userId
*/
void removeById(Long id, Long userId);
实现:PatientServiceImpl
@Override
public void removeById(Long id, Long userId) {
LambdaQueryWrapper<Patient> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Patient::getUserId, userId).eq(Patient::getId, id);
baseMapper.delete(queryWrapper);
}
创建api/patient.js
import request from '~/utils/request'
export default {
save(patient) {
return request({
url: `/front/user/patient/auth/save`,
method: 'post',
data: patient
})
},
updateById(patient) {
return request({
url: `/front/user/patient/auth/update`,
method: 'put',
data: patient
})
},
getById(id) {
return request({
url: `/front/user/patient/auth/get/${id}`,
method: 'get'
})
},
findList() {
return request({
url: `/front/user/patient/auth/findAll`,
method: `get`
})
},
removeById(id) {
return request({
url: `/front/user/patient/auth/remove/${id}`,
method: 'delete'
})
}
}
资料:资料>就诊人管理>
就诊人列表:pages/patient/index.vue
就诊人添加与修改 :pages/patient/add.vue
就诊人详情与删除:pages/patient/show.vue
AdminUserInfoController:
package com.atguigu.syt.user.controller.admin;
@Api(tags = "用户管理接口")
@RestController
@RequestMapping("/admin/user/userInfo")
public class AdminUserInfoController {
@Resource
private UserInfoService userInfoService;
@ApiOperation("分页条件查询")
@ApiImplicitParams({
@ApiImplicitParam(name = "page",value = "页码",required = true),
@ApiImplicitParam(name = "limit",value = "每页记录数",required = true),
@ApiImplicitParam(name = "userInfoQueryVo",value = "查询对象",required = false)
})
@GetMapping("/{page}/{limit}")
public Result<IPage<UserInfo>> list(
@PathVariable Long page,
@PathVariable Long limit,
UserInfoQueryVo userInfoQueryVo
) {
Page<UserInfo> pageParam = new Page<>(page,limit);
IPage<UserInfo> pageModel = userInfoService.selectPage(pageParam, userInfoQueryVo);
return Result.ok(pageModel);
}
}
Service接口:UserInfoService
/**
* 查询用户分页列表
* @param pageParam
* @param userInfoQueryVo
* @return
*/
IPage<UserInfo> selectPage(Page<UserInfo> pageParam, UserInfoQueryVo userInfoQueryVo);
Service实现:UserInfoServiceImpl
@Override
public IPage<UserInfo> selectPage(Page<UserInfo> pageParam, UserInfoQueryVo userInfoQueryVo) {
//UserInfoQueryVo获取条件值
String keyword = userInfoQueryVo.getKeyword(); //用户名称
String createTimeBegin = userInfoQueryVo.getCreateTimeBegin(); //开始时间
String createTimeEnd = userInfoQueryVo.getCreateTimeEnd(); //结束时间
//对条件值进行非空判断
LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.and(!StringUtils.isEmpty(keyword),
i -> i.like(UserInfo::getName, keyword).or().like(UserInfo::getPhone, keyword))
.ge(!StringUtils.isEmpty(createTimeBegin), UserInfo::getCreateTime, createTimeBegin)
.le(!StringUtils.isEmpty(createTimeEnd), UserInfo::getCreateTime, createTimeEnd);
//调用mapper的方法
IPage<UserInfo> pages = baseMapper.selectPage(pageParam, wrapper);
//编号变成对应值封装
pages.getRecords().forEach(this::packUserInfoForList);
return pages;
}
辅助方法:
/**
* 封装用户状态、认证状态、证件类型信息
* @param userInfo
* @return
*/
private UserInfo packUserInfoForList(UserInfo userInfo) {
//判断用户是否已经提交实名认证
if(userInfo.getAuthStatus().intValue() != AuthStatusEnum.NO_AUTH.getStatus().intValue()){
String certificatesTypeString = dictFeignClient.getName(
DictTypeEnum.CERTIFICATES_TYPE.getDictTypeId(),
userInfo.getCertificatesType()
);
userInfo.getParam().put("certificatesTypeString", certificatesTypeString);
}
userInfo.getParam().put("authStatusString", AuthStatusEnum.getStatusNameByStatus(userInfo.getAuthStatus()));
userInfo.getParam().put("statusString", UserStatusEnum.getStatusNameByStatus(userInfo.getStatus()));
return userInfo;
}
Controller:在AdminUserInfoController中添加方法
@ApiOperation("锁定和解锁")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId",value = "用户id",required = true),
@ApiImplicitParam(name = "status",value = "用户状态",required = true)
})
@PutMapping("lock/{userId}/{status}")
public Result lock(
@PathVariable("userId") Long userId,
@PathVariable("status") Integer status){
boolean result = userInfoService.lock(userId, status);
if(result){
return Result.ok().message("设置成功");
}else{
return Result.ok().message("设置失败");
}
}
Service接口:UserInfoService
/**
* 锁定和解锁用户
* @param userId
* @param status
* @return
*/
boolean lock(Long userId, Integer status);
Service实现:UserInfoServiceImpl
@Override
public boolean lock(Long userId, Integer status) {
if(status == 0 || status == 1){
UserInfo userInfo = new UserInfo();
userInfo.setId(userId);
userInfo.setStatus(status);
return this.updateById(userInfo);
}
return false;
}
Controller:在AdminUserInfoController中添加方法
@ApiOperation("用户详情")
@ApiImplicitParam(name = "userId",value = "用户id",required = true)
@GetMapping("show/{userId}")
public Result<Map<String, Object>> show(@PathVariable Long userId) {
return Result.ok(userInfoService.show(userId));
}
Service接口:UserInfoService
/**
* 根据用户id获取用户详情
* @param userId
* @return
*/
Map<String, Object> show(Long userId);
Service实现:UserInfoServiceImpl
@Resource
private PatientService patientService;
@Override
public Map<String, Object> show(Long userId) {
Map<String,Object> map = new HashMap<>();
//根据userid查询用户信息
UserInfo userInfo = this.packUserInfo(baseMapper.selectById(userId));
map.put("userInfo",userInfo);
//根据userid查询就诊人信息
List<Patient> patientList = patientService.findByUserId(userId);
map.put("patientList",patientList);
return map;
}
Controller:在AdminUserInfoController中添加方法
@ApiOperation("认证审批")
@ApiImplicitParams({
@ApiImplicitParam(name = "userId",value = "用户id",required = true),
@ApiImplicitParam(name = "authStatus",value = "用户认证审批状态",required = true)
})
@PutMapping("approval/{userId}/{authStatus}")
public Result approval(@PathVariable Long userId, @PathVariable Integer authStatus) {
boolean result = userInfoService.approval(userId,authStatus);
if(result){
return Result.ok().message("审批成功");
}else{
return Result.ok().message("审批失败");
}
}
Service接口:UserInfoService
/**
* 审核用户
* @param userId
* @param authStatus
* @return
*/
boolean approval(Long userId, Integer authStatus);
Service实现:UserInfoServiceImpl
/**
* 认证审批 2通过 -1不通过
* @param userId
* @param authStatus
* @return
*/
@Override
public boolean approval(Long userId, Integer authStatus) {
if(authStatus == AuthStatusEnum.AUTH_SUCCESS.getStatus()
|| authStatus == AuthStatusEnum.AUTH_FAIL.getStatus()){
UserInfo userInfo = new UserInfo();
userInfo.setId(userId);
userInfo.setAuthStatus(authStatus);
return this.updateById(userInfo);
}
return false;
}
在后台管理系统前端项目中添加如下页面,资料:资料>用户管理
用户列表:src/views/syt/userInfo/list.vue
用户详情,详情页面展示用户信息、用户就诊人信息:src/views/syt/userInfo/show.vue
静态路由:
{
path: '/userInfo',
component: Layout,
redirect: '/userInfo/list',
name: 'userInfo',
meta: { title: '用户管理', icon: 'user' },
alwaysShow: true,
children: [
{
path: 'list',
name: 'userInfoList',
component: () => import('@/views/syt/userInfo/list'),
meta: { title: '用户列表', icon: 'el-icon-s-unfold' }
},
{
path: 'show/:id',
name: 'userInfoShow',
component: () => import('@/views/syt/userInfo/show'),
meta: { title: '查看用户' },
hidden: true
}
]
},
动态路由:
用户管理:
用户列表:
查看用户:
创建src/api/syt/userInfo.js
import request from '@/utils/request'
const apiName = '/admin/user/userInfo'
export default {
//用户列表
getPageList(page, limit, searchObj) {
return request({
url: `${apiName}/${page}/${limit}`,
method: 'get',
params: searchObj
})
},
//锁定与解锁
lock(id, status) {
return request({
url: `${apiName}/lock/${id}/${status}`,
method: 'put'
})
},
//用户详情
show(id) {
return request({
url: `${apiName}/show/${id}`,
method: 'get'
})
},
//认证审批
approval(id, authStatus) {
return request({
url: `${apiName}/approval/${id}/${authStatus}`,
method: 'put'
})
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章