3. 用户登录
- element ui admin 执行流程图
3.0 取消登录表单校验
3.1 发送验证码邮件
3.1.1 前端:显示表单
- 登录页面:
@/views/login/index.vue
<!-- 邮箱 --> <el-form-item prop="email"> <span class="svg-container"> <svg-icon icon-class="email" /> </span> <el-input ref="email" v-model="loginForm.email" placeholder="请输入邮箱" name="email" type="text" tabindex="3" style="width:70%;" /> <el-button type="primary" style="width:20%" @click.native.prevent="sendEmail">发送</el-button> </el-form-item> <!-- 验证码 --> <el-form-item prop="verifycode"> <span class="svg-container"> <svg-icon icon-class="guide" /> </span> <el-input ref="verifycode" v-model="loginForm.verifycode" placeholder="请输入验证码" name="verifycode" type="text" tabindex="4" /> </el-form-item>
3.1.2 前端:发送邮件
- 编写API,发送邮件
export function send(user) { return axios.post('/user-service/user/sendemail',user); }
- 调用
async sendEmail() { let { message } = await send( this.loginForm) this.$message.success( message ) }
3.1.3 完善 EduUser
- 用于封装表单提交的用户数据
package com.czxy.zx.domain; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModel; import lombok.Data; import java.util.Date; /** * */ @Data //@TableName("edu_user") @ApiModel(value = "EduUser对象",description = "用户") public class EduUser { @TableId(value="id" , type = IdType.AUTO) private Integer id; //用户名 private String username; //用户密码 private String password; //电话 private String phone; //邮箱 private String email; //角色,多个值使用逗号分隔,例如:admin,editor private String roles; //创建时间 private Date created; //状态:0 未激活、1已激活 private String status; @TableField(exist = false) private String verifycode; }
3.1.4 用于封装与MQ交互的数据
package com.czxy.zx.vo; import lombok.Data; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Data public class UserEmail { private String username; private String email; private String text; }
3.1.5 编写Rabbit配置类
package com.czxy.zx.user.config; import org.springframework.amqp.core.Queue; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Component public class RabbitEmailConfig { // 队列的名称 public static final String QUEUE_NAME = "zx-email"; @Bean public Queue queue() { return new Queue(QUEUE_NAME); } }
3.1.6 后端实现
/** * @author 桐叔 * @email liangtong@itcast.cn */ @RestController @RequestMapping("/user") public class EduUserController { @Resource private EduUserService eduUserService; @Resource private StringRedisTemplate stringRedisTemplate; @Resource private RabbitTemplate rabbitTemplate; @PostMapping("/sendemail") public BaseResult sendemail(@RequestBody EduUser eduUser) { //1 随机字符串 Random random = new Random(); // [0,8999) --> [1000,9999) int randomNumber = random.nextInt(8999) + 1000; //2 发送redis一份 stringRedisTemplate.opsForValue().set("login" + eduUser.getUsername(), randomNumber + ""); //3 mq存放 UserEmail userEmail = new UserEmail(); userEmail.setUsername(eduUser.getUsername()); userEmail.setEmail(eduUser.getEmail()); userEmail.setText("登录验证码是:" + randomNumber); String userEmailStr = JSONObject.toJSONString(userEmail); rabbitTemplate.convertAndSend(RabbitEmailConfig.QUEUE_NAME , userEmailStr); return BaseResult.ok("发送中,请查收"); }
3.2 编写MQ:发送邮件
3.2.1 拷贝配置类
- 与登录模块使用的配置类相同
package com.czxy.zx.config; import org.springframework.amqp.core.Queue; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Component public class RabbitEmailConfig { // 队列的名称 public static final String QUEUE_NAME = "zx-email"; @Bean public Queue queue() { return new Queue(QUEUE_NAME); } }
3.2.2 监听器发送邮件
package com.czxy.zx.listener; import com.alibaba.fastjson.JSONObject; import com.czxy.zx.config.RabbitEmailConfig; import com.czxy.zx.utils.EmailUtils; import com.czxy.zx.vo.UserEmail; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author 桐叔 * @email liangtong@itcast.cn */ @Component public class RabbitEmailListener { @Resource private JavaMailSender javaMailSender; @RabbitListener(queues = RabbitEmailConfig.QUEUE_NAME) public void sendEmail(String message) { //1 将消息转换成 UserEmail UserEmail userEmail = JSONObject.parseObject(message, UserEmail.class); //2 发送邮件,如果邮箱为空,将出现循环异常 if(userEmail.getEmail() != null) { EmailUtils.sendEmail(javaMailSender,userEmail.getEmail(),userEmail.getText()); } } }
3.3 后端:用户登录
3.3.0 前端登录流程
- 步骤一:登录页面
@/views/login/index.vue
步骤二:登录调用 vuex
步骤三:查看vuex
步骤四:调用ajax
- 步骤五:确定ajax发送位置
3.3.1 修改前端api
export function login(user) { // 真实数据 return axios.post('/user-service/user/login',user); // 临时模拟 // return axios.post('/teacher-service/user/login',user); }
3.3.2 修改前端请求数据
3.3.2 后端实现
- EduUserController 添加 login 方法
package com.czxy.zx.user.controller; import com.alibaba.fastjson.JSON; import com.czxy.zx.domain.EduUser; import com.czxy.zx.user.config.RabbitEmailConfig; import com.czxy.zx.user.service.EduUserService; import com.czxy.zx.vo.BaseResult; import com.czxy.zx.vo.UserEmail; import org.apache.commons.lang3.RandomUtils; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; /** * @author 桐叔 * @email liangtong@itcast.cn */ @RestController @RequestMapping("/user") public class EduUserController { @Resource private EduUserService eduUserService; @Resource private RabbitTemplate rabbitTemplate; @Resource private StringRedisTemplate stringRedisTemplate; @PostMapping("/send") public BaseResult send(@RequestBody EduUser eduUser) { //1 随机生成验证码 int num = RandomUtils.nextInt(1000, 10000); //2 封装发送邮件的数据-- UserEmail userEmail = new UserEmail(); userEmail.setEmail(eduUser.getEmail()); userEmail.setTitle("用户登录验证码"); userEmail.setText(eduUser.getUsername() + "您好,本次验证码:" + num); //3 发送邮件-将邮件信息存放mq String jsonStr = JSON.toJSONString(userEmail); rabbitTemplate.convertAndSend("", RabbitEmailConfig.QUEUE_NAME, jsonStr); //4 将验证码存放redis String redisName = "login_verify_code_" + eduUser.getUsername(); stringRedisTemplate.opsForValue().set(redisName, num + ""); //5 提示 return BaseResult.ok("验证码发送成功!"); } @PostMapping("/login") public BaseResult login(@RequestBody EduUser eduUser) { //1 校验验证码 // 1.1 获得redis String redisName = "login_verify_code_" + eduUser.getUsername(); String redisVerifyCode = stringRedisTemplate.opsForValue().get(redisName); // 1.2 删除redis stringRedisTemplate.delete(redisName); // 1.3 校验:无效 if(redisVerifyCode == null) { return BaseResult.error("验证码无效"); } // 1.4 校验:错误 if(!redisVerifyCode.equalsIgnoreCase(eduUser.getVerifycode())) { return BaseResult.error("验证码错误"); } //2 通过service用户登录 EduUser loginUser = eduUserService.login(eduUser); //3 提示 if(loginUser != null) { // 需要设置token String token = "admin-token"; return BaseResult.ok("登录成功").append("token", token); } return BaseResult.error("用户名或密码不匹配"); } }
3.3.4 前端修改
3.3.5 数据要求 admin-token
登录成功后,查询用户详情的使用
3.4 登录成功后查询权限
3.4.1 分析
- 登录时,返回一个固定的字符串:admin-token 或 editor-token
- 登录成功后,查询用户详情将携带固定字符串
根据固定字符串查询用户的权限,并返回固定的信息:
{ roles: ['admin'], //用户角色 或 [editor] 或 [admin,editor] avatar: '', //头像图片地址 name: '', //用户名 }
查询详情ajax调用时机
3.4.2 前端完善
3.4.3 后端实现
- 完善 EduUserController,添加查询详情功能
/** * 查询详情 * @param token * @return */ @GetMapping("/info") public BaseResult info(String token) { System.out.println(token); Map<String,Object> map = new HashMap<>(); // 根据固定字符串拼凑数据 if("admin-token".equals(token)) { map.put("roles", Arrays.asList("admin")); map.put("avatar","https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif"); map.put("name","Super Admin"); } else { map.put("roles", Arrays.asList("editor")); map.put("avatar","https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif"); map.put("name","Normal Editor"); } return BaseResult.ok("成功", map); }