用户界面操作&登录&JWT&短信验证&用户认证网关整合

用户首页数据分析

1,获取医院等级(根据数据字典编码获取)
2,获取地区(根据数据字典编码获取)
3,医院分页列表
4,根据医院名称关键字搜索医院列表
所有的后端接口都在HospitalApiController中
在这里插入图片描述

医院详情页

  • 左侧预约挂号:获取科室信息和挂号规则
  • 医院详情和预约规则调用一个接口,返回map
    @Override
    public Map<String, Object> item(String hoscode) {
        Map<String, Object> result = new HashMap<>();
        //医院详情
        Hospital hospital = this.setHospitalHosType(this.getByHoscode(hoscode));
        result.put("hospital", hospital);
        //预约规则
        result.put("bookingRule", hospital.getBookingRule());
        //不需要重复返回
        hospital.setBookingRule(null);
        return result;
    }

在这里插入图片描述

登录

登录需求

1,登录采取弹出层的形式
2,登录方式:
(1)手机号码+手机验证码
(2)微信扫描
3,无注册界面,第一次登录根据手机号判断系统是否存在,如果不存在则自动注册
4,微信扫描登录成功必须绑定手机号码,即:第一次扫描成功后绑定手机号,以后登录扫描直接登录成功
5,网关统一判断登录状态,如何需要登录,页面弹出登录层,不要session

login校验步骤

  • 获取手机号和验证码
  • 校验参数
  • TODO 校验验证码(第三方短信服务)
  • 校验是否被禁用 (判断status)
  • JWT生成token
  • userInfo不为空,返回页面显示名称
@Service
public class UserInfoServiceImpl extends
        ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public Map<String, Object> login(LoginVo loginVo) {

        //获取手机号和验证码
        String phone = loginVo.getPhone();
        String code = loginVo.getCode();
        //校验参数
        if(StringUtils.isEmpty(phone) ||
                StringUtils.isEmpty(code)) {
            throw new YyghException(ResultCodeEnum.PARAM_ERROR);
        }
        //TODO 校验校验验证码
        String mobleCode =  redisTemplate.opsForValue().get(phone).toString();
        if(!code.equals(mobleCode)) {
            throw new YyghException(ResultCodeEnum.CODE_ERROR);
        }

        //手机号已被使用
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        //获取会员
        UserInfo userInfo = baseMapper.selectOne(queryWrapper);
        if(null == userInfo) {
            //第一次使用该手机号
            userInfo = new UserInfo();
            userInfo.setName("");
            userInfo.setPhone(phone);
            userInfo.setStatus(1);
            baseMapper.insert(userInfo);
        }
        //校验是否被禁用
        if(userInfo.getStatus() == 0) {
            throw new YyghException(ResultCodeEnum.LOGIN_DISABLED_ERROR);
        }

        //userInfo不为空,返回页面显示名称
        Map<String, Object> map = new HashMap<>();
        String name = userInfo.getName();
        if(StringUtils.isEmpty(name)) {
            name = userInfo.getNickName();
        }
        if(StringUtils.isEmpty(name)) {
            name = userInfo.getPhone();
        }
        //TODO 生成token记录登录
        String token = JwtHelper.createToken(userInfo.getId(), name);
        map.put("name", name);
        map.put("token", token);
        return map;

    }
}

JWT在这里插入图片描述

短信验证

  • 调用第三方服务发送验证码短信
  • 在前端中,二种登录方式,手机号,微信,优先使用手机号登录(设置一个默认值优先手机号登录)
  • 发送短信验证码,调用后端msm中sendcode接口。
  • 设置倒计时时间60s,setInterval方法。
  • 验证码输入后,调用后端login接口进行登录验证,登录成功则设置cookies(name和token)

在这里插入图片描述

全局登录监听事件

目前登录层在myheader组件里面,登录按钮也在同一个组件里面,我们点击登录,调用showLogin()方法即可
目前的问题是,我们在预约挂号页面,选择科室去挂号时我们需要判断当前是否登录,如果登录可以进入下一个页面;如果没有登录需要显示登录层,那么这个问题怎么解决呢,我们不能直接调用头部登录方法,我们目前的组件是包含在nuxt里面的
问题总是能够解决的,其实很简单,我们可以注册一个全局登录监听事件,当需要登录层时,我们发送一个登录事件,头部监听登录事件,然后我们触发登录按钮的点击事件即可打开登录层。

mounted() {
// 注册全局登录事件对象
window.loginEvent = new Vue();
// 监听登录事件
loginEvent.$on('loginDialogEvent', function () {
document.getElementById("loginDialog").click();
  })
// 触发事件,显示登录层:loginEvent.$emit('loginDialogEvent')
}

用户认证网关整合

思路:

  1. 所有请求都会经过服务网关,服务网关对外暴露服务,在网关进行统一用户认证;
  2. 既然要在网关进行用户认证,网关得知道对哪些url进行认证,所以我们得对ur制定规则
  3. Api接口异步请求的,我们采取url规则匹配,如:/api//auth/,如凡是满足该规则的都必须用户认证
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getURI().getPath();
        System.out.println("==="+path);

        //内部服务接口,不允许外部访问
        if(antPathMatcher.match("/**/inner/**", path)) {
            ServerHttpResponse response = exchange.getResponse();
            return out(response, ResultCodeEnum.PERMISSION);
        }

        Long userId = this.getUserId(request);
        //api接口,异步请求,校验用户必须登录
        if(antPathMatcher.match("/api/**/auth/**", path)) {
            if(StringUtils.isEmpty(userId)) {
                ServerHttpResponse response = exchange.getResponse();
                return out(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }
        return chain.filter(exchange);
    }

在服务网关中判断用户登录状态

(看token有没有)
我们统一从header头信息中获取
如何判断用户信息合法:
登录时我们返回用户token,在服务网关中获取到token后,我在到redis中去查看用户id,如何用户id存在,则token合法,否则不合法

前端修改

请求服务器端接口时我们默认带上token,需要登录的接口如果token没有或者token过期,服务器端会返回208状态,然后发送登录事件打开登录弹出层登录
在前端request.js中,修改。因为在myheader.vue中已经定义过全局登录监听事件,这里状态码208,就会弹出登录框

if(response.data.code === 208) {
            //弹出登录输入框
            loginEvent.$emit('loginDialogEvent')
            return
        }

版权声明:本文为weixin_44479101原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。