【探花交友】用户登录、代码优化

ゝ一世哀愁。 2024-04-07 15:49 201阅读 0赞

文章目录

7、用户登录

7.1、登录验证码

7.2、JWT

7.3、用户登录

8、代码优化

8.1 抽取BasePojo

8.2 自动填充

7、用户登录

7.1、登录验证码

3de0a36429f0444b97121355af6fba71.png

7.1.1、接口说明

0590cb60bfb34021a187992d6b5ccda4.png

参见YAPI接口地址:http://192.168.136.160:3000/project/19/interface/api/94

7.1.2、流程分析

edc02e493b6a4d97af07184b8cb34923.png

客户端发送请求

服务端调用第三方组件发送验证码

验证码发送成功,存入redis

响应客户端,客户端跳转到输入验证码页面

7.1.3、代码实现

LoginController

  1. @RestController
  2. @RequestMapping("/user")
  3. public class LoginController {
  4. @Autowired
  5. private UserService userService;
  6. /**
  7. * 获取登录验证码
  8. * 请求参数:phone (Map)
  9. * 响应:void
  10. */
  11. @PostMapping("/login")
  12. public ResponseEntity login(@RequestBody Map map){
  13. String phone =(String) map.get("phone");
  14. userService.sendMsg(phone);
  15. return ResponseEntity.ok(null); //正常返回状态码200
  16. }
  17. }

UserService

  1. @Service
  2. public class UserService {
  3. @Autowired
  4. private SmsTemplate template;
  5. @Autowired
  6. private RedisTemplate<String,String> redisTemplate;
  7. /**
  8. * 发送短信验证码
  9. * @param phone
  10. */
  11. public void sendMsg(String phone) {
  12. //1、随机生成6位数字
  13. //String code = RandomStringUtils.randomNumeric(6);
  14. String code = "123456";
  15. //2、调用template对象,发送手机短信
  16. //template.sendSms(phone,code);
  17. //3、将验证码存入到redis
  18. redisTemplate.opsForValue().set("CHECK_CODE_"+phone,code, Duration.ofMinutes(5));
  19. }
  20. }

7.2、JWT

7.2.1、简介

JSON Web token简称JWT, 是用于对应用程序上的用户进行身份验证的标记。也就是说, 使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他session数据。此特性便于可伸缩性, 同时保证应用程序的安全

7.2.2、格式

  • JWT就是一个字符串,经过加密处理与校验处理的字符串,形式为:A.B.C
  • A由JWT头部信息header加密得到
  • B由JWT用到的身份验证信息json数据加密得到
  • C由A和B加密得到,是校验部分

9f7803e030254fc2aa490559a1344d6c.png

7.2.3、流程

f8c7a975894d425fa8d49a44bde19aa5.png

7.2.4、示例

导入依赖:

  1. <dependency>
  2. <groupId>io.jsonwebtoken</groupId>
  3. <artifactId>jjwt</artifactId>
  4. <version>0.9.1</version>
  5. </dependency>

编写测试用例:

  1. @Test
  2. public void testCreateToken() {
  3. //生成token
  4. //1、准备数据
  5. Map map = new HashMap();
  6. map.put("id",1);
  7. map.put("mobile","13800138000");
  8. //2、使用JWT的工具类生成token
  9. long now = System.currentTimeMillis();
  10. String token = Jwts.builder()
  11. .signWith(SignatureAlgorithm.HS512, "itcast") //指定加密算法
  12. .setClaims(map) //写入数据
  13. .setExpiration(new Date(now + 30000)) //失效时间
  14. .compact();
  15. System.out.println(token);
  16. }
  17. //解析token
  18. /**
  19. * SignatureException : token不合法
  20. * ExpiredJwtException:token已过期
  21. */
  22. @Test
  23. public void testParseToken() {
  24. String token = "eyJhbGciOiJIUzUxMiJ9.eyJtb2JpbGUiOiIxMzgwMDEzODAwMCIsImlkIjoxLCJleHAiOjE2MTgzOTcxOTV9.2lQiovogL5tJa0px4NC-DW7zwHFqZuwhnL0HPAZunieGphqnMPduMZ5TtH_mxDrgfiskyAP63d8wzfwAj-MIVw";
  25. try {
  26. Claims claims = Jwts.parser()
  27. .setSigningKey("itcast")
  28. .parseClaimsJws(token)
  29. .getBody();
  30. Object id = claims.get("id");
  31. Object mobile = claims.get("mobile");
  32. System.out.println(id + "--" + mobile);
  33. }catch (ExpiredJwtException e) {
  34. System.out.println("token已过期");
  35. }catch (SignatureException e) {
  36. System.out.println("token不合法");
  37. }
  38. }

通过解析Token得知,如果抛出SignatureException异常表示token不合法,如果抛出ExpiredJwtException异常表示token已过期

7.2.5 JWT工具类

  1. public class JwtUtils {
  2. // TOKEN的有效期1小时(S)
  3. private static final int TOKEN_TIME_OUT = 1 * 3600;
  4. // 加密KEY
  5. private static final String TOKEN_SECRET = "itcast";
  6. // 生成Token
  7. public static String getToken(Map params){
  8. long currentTime = System.currentTimeMillis();
  9. return Jwts.builder()
  10. .signWith(SignatureAlgorithm.HS512, TOKEN_SECRET) //加密方式
  11. .setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //过期时间戳
  12. .addClaims(params)
  13. .compact();
  14. }
  15. /**
  16. * 获取Token中的claims信息
  17. */
  18. public static Claims getClaims(String token) {
  19. return Jwts.parser()
  20. .setSigningKey(TOKEN_SECRET)
  21. .parseClaimsJws(token).getBody();
  22. }
  23. /**
  24. * 是否有效 true-有效,false-失效
  25. */
  26. public static boolean verifyToken(String token) {
  27. if(StringUtils.isEmpty(token)) {
  28. return false;
  29. }
  30. try {
  31. Claims claims = Jwts.parser()
  32. .setSigningKey("itcast")
  33. .parseClaimsJws(token)
  34. .getBody();
  35. }catch (Exception e) {
  36. return false;
  37. }
  38. return true;
  39. }
  40. }

7.3、用户登录

用户接收到验证码后,进行输入验证码,点击登录,前端系统将手机号以及验证码提交到服务端进行校验。

27d065b2e28f40e199f2836dafbc9582.png

7.3.1、接口文档

41fd56636b344aeb937e5c3437099d1b.png

YAPI接口地址:YApi-高效、易用、功能强大的可视化接口管理平台

7.3.2、LoginController

  1. /**
  2. * 检验登录
  3. */
  4. @PostMapping("/loginVerification")
  5. public ResponseEntity loginVerification(@RequestBody Map map) {
  6. //1、调用map集合获取请求参数
  7. String phone = (String) map.get("phone");
  8. String code = (String) map.get("verificationCode");
  9. //2、调用userService完成用户登录
  10. Map retMap = userService.loginVerification(phone,code);
  11. //3、构造返回
  12. return ResponseEntity.ok(retMap);
  13. }

7.3.3、UserService

  1. /**
  2. * 验证登录
  3. * @param phone
  4. * @param code
  5. */
  6. public Map loginVerification(String phone, String code) {
  7. //1、从redis中获取下发的验证码
  8. String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + phone);
  9. //2、对验证码进行校验(验证码是否存在,是否和输入的验证码一致)
  10. if(StringUtils.isEmpty(redisCode) || !redisCode.equals(code)) {
  11. //验证码无效
  12. throw new RuntimeException();
  13. }
  14. //3、删除redis中的验证码
  15. redisTemplate.delete("CHECK_CODE_" + phone);
  16. //4、通过手机号码查询用户
  17. User user = userApi.findByMobile(phone);
  18. boolean isNew = false;
  19. //5、如果用户不存在,创建用户保存到数据库中
  20. if(user == null) {
  21. user = new User();
  22. user.setMobile(phone);
  23. user.setPassword(DigestUtils.md5Hex("123456"));
  24. Long userId = userApi.save(user);
  25. user.setId(userId);
  26. isNew = true;
  27. }
  28. //6、通过JWT生成token(存入id和手机号码)
  29. Map tokenMap = new HashMap();
  30. tokenMap.put("id",user.getId());
  31. tokenMap.put("mobile",phone);
  32. String token = JwtUtils.getToken(tokenMap);
  33. //7、构造返回值
  34. Map retMap = new HashMap();
  35. retMap.put("token",token);
  36. retMap.put("isNew",isNew);
  37. return retMap;
  38. }

7.3.4、测试

36b5d19a629c443b8ef40bb00594bda6.png

8、代码优化

8.1 抽取BasePojo

为了简化实体类中created和updated字段,抽取BasePojo

  1. @Data
  2. public abstract class BasePojo implements Serializable {
  3. @TableField(fill = FieldFill.INSERT) //自动填充
  4. private Date created;
  5. @TableField(fill = FieldFill.INSERT_UPDATE)
  6. private Date updated;
  7. }

8.2 自动填充

对于created和updated字段,每次操作都需要手动设置。为了解决这个问题,mybatis-plus支持自定义处理器的形式实现保存更新的自动填充

  1. package com.tanhua.dubbo.server.handler;
  2. import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
  3. import org.apache.ibatis.reflection.MetaObject;
  4. import org.springframework.stereotype.Component;
  5. import java.util.Date;
  6. @Component
  7. public class MyMetaObjectHandler implements MetaObjectHandler {
  8. @Override
  9. public void insertFill(MetaObject metaObject) {
  10. Object created = getFieldValByName("created", metaObject);
  11. if (null == created) {
  12. //字段为空,可以进行填充
  13. setFieldValByName("created", new Date(), metaObject);
  14. }
  15. Object updated = getFieldValByName("updated", metaObject);
  16. if (null == updated) {
  17. //字段为空,可以进行填充
  18. setFieldValByName("updated", new Date(), metaObject);
  19. }
  20. }
  21. @Override
  22. public void updateFill(MetaObject metaObject) {
  23. //更新数据时,直接更新字段
  24. setFieldValByName("updated", new Date(), metaObject);
  25. }
  26. }

发表评论

表情:
评论列表 (有 0 条评论,201人围观)

还没有评论,来说两句吧...

相关阅读

    相关 交友项目面试分析

    1、项目介绍 探花交友是一个陌生人在线交友平台,在该平台中可以搜索附近的人,查看好友动态,平台提供大数据分析,通过后台推荐系统帮我们快速匹配自己的“意中人”。项目主要分为