当前位置: 首页 > news >正文

微服务项目:尚融宝(28)(后端搭建:实现用户登录(1))

认清现实,放弃幻想,准备斗争

需求

一、后端的接口

1、集成JWT

service-base中添加依赖

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
</dependency>

2、JWT工具

service-base中添加util包

添加JwtUtils类

public class JwtUtils {

    private static long tokenExpiration = 24*60*60*1000;
    private static String tokenSignKey = "A1t2g3uigu123456";

    private static Key getKeyInstance(){
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        byte[] bytes = DatatypeConverter.parseBase64Binary(tokenSignKey);
        return new SecretKeySpec(bytes,signatureAlgorithm.getJcaName());
    }

    public static String createToken(Long userId, String userName) {
        String token = Jwts.builder()
                .setSubject("SRB-USER")
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .claim("userId", userId)
                .claim("userName", userName)
                .signWith(SignatureAlgorithm.HS512, getKeyInstance())
                .compressWith(CompressionCodecs.GZIP)
                .compact();
        return token;
    }

    /**
     * 判断token是否有效
     * @param token
     * @return
     */
    public static boolean checkToken(String token) {
        if(StringUtils.isEmpty(token)) {
            return false;
        }
        try {
            Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    public static Long getUserId(String token) {
        Claims claims = getClaims(token);
        Integer userId = (Integer)claims.get("userId");
        return userId.longValue();
    }

    public static String getUserName(String token) {
        Claims claims = getClaims(token);
        return (String)claims.get("userName");
    }

    public static void removeToken(String token) {
        //jwttoken无需删除,客户端扔掉即可。
    }

    /**
     * 校验token并返回Claims
     * @param token
     * @return
     */
    private static Claims getClaims(String token) {
        if(StringUtils.isEmpty(token)) {
            // LOGIN_AUTH_ERROR(-211, "未登录"),
            throw new BusinessException(ResponseEnum.LOGIN_AUTH_ERROR);
        }
        try {
            Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
            Claims claims = claimsJws.getBody();
            return claims;
        } catch (Exception e) {
            throw new BusinessException(ResponseEnum.LOGIN_AUTH_ERROR);
        }
    }
}

3、创建VO对象

service-core中创建登录对象

@Data
@ApiModel(description="登录对象")
public class LoginVO {
    
    @ApiModelProperty(value = "用户类型")
    private Integer userType;

    @ApiModelProperty(value = "手机号")
    private String mobile;

    @ApiModelProperty(value = "密码")
    private String password;
}

用户信息对象 

@Data
@ApiModel(description="用户信息对象")
public class UserInfoVO {

    @ApiModelProperty(value = "用户姓名")
    private String name;

    @ApiModelProperty(value = "用户昵称")
    private String nickName;
    
    @ApiModelProperty(value = "头像")
    private String headImg;
    
    @ApiModelProperty(value = "手机号")
    private String mobile;

    @ApiModelProperty(value = "1:出借人 2:借款人")
    private Integer userType;

    @ApiModelProperty(value = "JWT访问令牌")
    private String token;
}

4、Controller

UserInfoController

@ApiOperation("会员登录")
@PostMapping("/login")
public R login(@RequestBody LoginVO loginVO, HttpServletRequest request) {

    String mobile = loginVO.getMobile();
    String password = loginVO.getPassword();
    Assert.notEmpty(mobile, ResponseEnum.MOBILE_NULL_ERROR);
    Assert.notEmpty(password, ResponseEnum.PASSWORD_NULL_ERROR);

    String ip = request.getRemoteAddr();
    UserInfoVO userInfoVO = userInfoService.login(loginVO, ip);

    return R.ok().data("userInfo", userInfoVO);
}

5、Service

接口:UserInfoService

UserInfoVO login(LoginVO loginVO, String ip);

实现:UserInfoServiceImpl 

@Resource
private UserLoginRecordMapper userLoginRecordMapper;

@Transactional( rollbackFor = {Exception.class})
@Override
public UserInfoVO login(LoginVO loginVO, String ip) {
    String mobile = loginVO.getMobile();
    String password = loginVO.getPassword();
    Integer userType = loginVO.getUserType();

    //获取会员
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("mobile", mobile);
    queryWrapper.eq("user_type", userType);
    UserInfo userInfo = baseMapper.selectOne(queryWrapper);

    //用户不存在
    //LOGIN_MOBILE_ERROR(-208, "用户不存在"),
    Assert.notNull(userInfo, ResponseEnum.LOGIN_MOBILE_ERROR);

    //校验密码
    //LOGIN_PASSWORD_ERROR(-209, "密码不正确"),
    Assert.equals(MD5.encrypt(password), userInfo.getPassword(), ResponseEnum.LOGIN_PASSWORD_ERROR);

    //用户是否被禁用
    //LOGIN_DISABLED_ERROR(-210, "用户已被禁用"),
    Assert.equals(userInfo.getStatus(), UserInfo.STATUS_NORMAL, ResponseEnum.LOGIN_LOKED_ERROR);

    //记录登录日志
    UserLoginRecord userLoginRecord = new UserLoginRecord();
    userLoginRecord.setUserId(userInfo.getId());
    userLoginRecord.setIp(ip);
    userLoginRecordMapper.insert(userLoginRecord);

    //生成token
    String token = JwtUtils.createToken(userInfo.getId(), userInfo.getName());
    UserInfoVO userInfoVO = new UserInfoVO();
    userInfoVO.setToken(token);
    userInfoVO.setName(userInfo.getName());
    userInfoVO.setNickName(userInfo.getNickName());
    userInfoVO.setHeadImg(userInfo.getHeadImg());
    userInfoVO.setMobile(userInfo.getMobile());
    userInfoVO.setUserType(userType);

    return userInfoVO;
}

 理清楚这里的业务逻辑:

1.先去查找用户是不是存在,如果不存在,马上断言失败退出逻辑

2.查看用户输入的密码是不是跟数据库中的数据是一样的,如果不是马上断言退出

3.查看用户状态是不是正常。如果不正常马上断言退出

4.记录登录日志

5.生产token

相关文章:

  • 【从零开始学习 SystemVerilog】4.2、SystemVerilog 进程—— disable fork join
  • 《算法系列》之动态规划
  • 【spring cloud】(六)消息总线——springcloud Bus
  • 【斯坦福大学公开课CS224W——图机器学习】一、图机器学习中的传统方法(1)
  • 【Java基础】TreeSet集合、自然排序、比较器排序、成绩排序及不重复随机数案例
  • Code For Better 谷歌开发者之声——Flutter - Google 开源的移动 UI 框架
  • 数据结构与算法01-算法的评估(大O表示法) 算法的优化方向
  • 某银行开发一个信用卡管理系统CCMS
  • JAVA基础知识
  • 计算机组成原理_数据寻址
  • Springboot集成Mybatisplus,轻松CRUD
  • IDEA生成时序图和类图(案例超详解)
  • 笔试选择题-树
  • 用神经网络模拟3个距离为0的粒子
  • 【重识云原生】第六章容器6.1.10节——DockerFile解析
  • 分享一款快速APP功能测试工具
  • angular学习第一篇-----环境搭建
  • echarts的各种常用效果展示
  • github从入门到放弃(1)
  • Java基本数据类型之Number
  • linux学习笔记
  • MySQL QA
  • python大佬养成计划----difflib模块
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • 从0实现一个tiny react(三)生命周期
  • 大主子表关联的性能优化方法
  • 电商搜索引擎的架构设计和性能优化
  • 基于Vue2全家桶的移动端AppDEMO实现
  • 坑!为什么View.startAnimation不起作用?
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 前嗅ForeSpider教程:创建模板
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 微信小程序:实现悬浮返回和分享按钮
  • 为什么要用IPython/Jupyter?
  • 我看到的前端
  • 移动端解决方案学习记录
  • 终端用户监控:真实用户监控还是模拟监控?
  • 2017年360最后一道编程题
  • scrapy中间件源码分析及常用中间件大全
  • #define
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (C++)栈的链式存储结构(出栈、入栈、判空、遍历、销毁)(数据结构与算法)
  • (solr系列:一)使用tomcat部署solr服务
  • (vue)页面文件上传获取:action地址
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (一)kafka实战——kafka源码编译启动
  • (转)用.Net的File控件上传文件的解决方案
  • (转载)Linux网络编程入门
  • ***检测工具之RKHunter AIDE
  • .bat批处理(九):替换带有等号=的字符串的子串
  • .NET 4 并行(多核)“.NET研究”编程系列之二 从Task开始
  • .net core使用ef 6
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。