个人博客(6、登录接口-2)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 个人博客(6、登录接口-2)

一、前言

在上一章中我对个人博客项目完成了登录接口,通过登录接口来整合redis和jwt,同时为创建UtilController,将一些公共接口放置在UtilController中

本章主要是完善上一章没有做完的功能, 主要是用户模块和完善登录接口, 包括用户的增删改查细节处理, 和登录接口的待完善内容(用户登录次数, 最后登录时间, 登录ip)

二, 用户模块增删改查

新增用户的注册时间,登录次数填充, 注册地ip, 信息判断, 密码加密

密码加密新增pom依赖和PasswordUtils工具类

<!--        实现SHA265加密-->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version> 1.15</version>
        </dependency>
复制代码
/**
 * 密码工具类
 * @Author ningxuan
 * @Date 2022/8/8 20:30
 */
public class PasswordUtils {
    /***
     * 利用Apache的工具类实现SHA-256加密
     *
     * @param str 加密后的报文
     * @return
     */
    public static String getSHA256Str(String str) {
        MessageDigest messageDigest;
        String encdeStr = "";
        try {
            messageDigest = MessageDigest.getInstance("SHA-256");
            byte[] hash = messageDigest.digest(str.getBytes("UTF-8"));
            encdeStr = Hex.encodeHexString(hash);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return encdeStr;
    }
}
复制代码

SysUserController

@PostMapping
@ApiOperation("新增")
public ResultVo insert(@RequestBody SysUserInsertDto userDto, HttpServletRequest request){
    // 判断username是否重复  true:null
    boolean b = sysUserService.userIsOnly(userDto.getUsername());
    if (!b){
        throw new BlogException(ErrorEnum.USER_EXIST_ERROR);
    }
    // 新增用户
    sysUserService.insert(userDto,request);
    return new ResultVo();
}
复制代码

SysUserServiceImpl

// 新增
@Override
public void insert(SysUserInsertDto userDto, HttpServletRequest request) {
    SysUser user = new SysUser();
    BeanUtils.copyProperties(userDto, user);
    user.setNum(1);
    user.setStatus("1");
    user.setCreateTime(LocalDateTime.now());
    // 获取用户注册ip
    String ipAddr = IpUtils.getIpAddr(request);
    user.setIpconfig(ipAddr);
    // 如果用户未填昵称则默认为username
    if (StringUtils.isEmpty(userDto.getNickname())){
        user.setNickname(userDto.getUsername());
    }
    // 密码加密
    user.setPassword(PasswordUtils.getSHA256Str(user.getPassword()));
    this.save(user);
}
// 判断username是否唯一
@Override
public boolean userIsOnly(String username) {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(SysUser::getUsername, username);
    SysUser user  = this.getOne(wrapper);
    return user == null;
}
复制代码

新建IPUtil类,用到了Common-lang3 jar包

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.8</version>
</dependency>
复制代码

用到了里面的StringUtils.isEmpty(final CharSequence cs)方法, 用来判断字符串是否为null

IpUtils工具类来自于人人开源,具体如下

public class IpUtils {
   private static Logger logger = LoggerFactory.getLogger(IpUtils.class);
   /**
    * 获取IP地址
    * 
    * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
    * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
    */
   public static String getIpAddr(HttpServletRequest request) {
       String unknown = "unknown";
       String ip = null;
        try {
            ip = request.getHeader("x-forwarded-for");
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_CLIENT_IP");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getHeader("HTTP_X_FORWARDED_FOR");
            }
            if (StringUtils.isEmpty(ip) || unknown.equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
        } catch (Exception e) {
           logger.error("IPUtils ERROR ", e);
        }
        return ip;
    }
}
复制代码

逻辑删除

使用了mybatis-plus的逻辑删除

网络异常,图片无法展示
|

修改时间填充, username不允许修改等

@Override
public void updateUser(SysUserUpdateDto userDto) {
    SysUser byId = this.getById(userDto.getBlid());
    if (byId == null){
        throw new BlogException(ErrorEnum.NOT_USER_ERROR);
    }
    SysUser user=  new SysUser();
    BeanUtils.copyProperties(userDto, user);
    // 更新修改时间
    user.setUpdateTime(LocalDateTime.now());
    this.updateById(user);
}
复制代码

查看列表

@Override
    public Page<SysUser> getList(PageVo page) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        // 可以根据keyword进行用户名的模糊查询
        wrapper.like(page.getKeyword() != null, SysUser::getNickname, page.getKeyword())
                // 只查询用户id, 昵称, 头像地址, 用户名, 最后登录时间
                .select(SysUser::getBlid,SysUser::getNickname,SysUser::getAvatar, SysUser::getUsername, SysUser::getLastLoginTime)
                // 查询账户状态正常的用户
                .eq(SysUser::getStatus, "1");
        Page<SysUser> pageList = new Page<>(page.getPage(), page.getSize());
        Page<SysUser> list = this.page(pageList, wrapper);
        return list;
    }
复制代码

查看详情

@GetMapping
    @ApiOperation("查看详情")
    public ResultVo getInfo(Long blid){
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getBlid, blid);
        SysUser one = sysUserService.getOne(wrapper);
        one.setPassword(null);
        return new ResultVo(one);
    }
复制代码

三、完善登录接口

用户不存在和密码错误使用自定义异常

@Override
public SysUser login(LoginDto loginDto, HttpServletResponse response) {
    LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
    wrapper.eq(SysUser::getUsername, loginDto.getUsername());
    SysUser one = this.getOne(wrapper);
    if (one == null){
        // 自定义异常
        log.error("用户不存在");
        throw new BlogException(ErrorEnum.USER_OR_PASSWORD_ERROR);
    }
    boolean equals = one.getPassword().equals(PasswordUtils.getSHA256Str(loginDto.getPassword()));
    if (!equals){
        // 自定义异常
        //TODO 密码错误之后生成token判断错误次数,超过五次锁用户
        log.error("账号或密码错误");
        throw new BlogException(ErrorEnum.USER_OR_PASSWORD_ERROR);
    }
    // 使用jwt生成token
    String token = JwtUtils.generateToken(one.getBlid());
    // 使用redis保存token   默认8小时
    redisUtils.set(RedisKeys.getLoginKey(token), one, CommonConstant.REDIS_TIME_TOKEN);
    // token存入cookie
    CookieUtils.setUpCookie(response, CommonConstant.COOKIE_TOKEN_KEY, token);
    return one;
}
复制代码

完善之前留下的CookieUtil工具类中不能获取到application.yml文件的配置

pom依赖下载

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
复制代码

类上添加@Component注解,主要是上面的依赖,不下载的话我添加注解也不好使

网络异常,图片无法展示
|

四、泛谈密码加密

明文存储密码毕竟有点不好, 本项目中采用了SHA265的形式存储密码

几种加密

由易到难可以分为

  • 前端加密
  • 前端、后端两至多次加密
  • 前端、后端(密码+加密盐)加密
  • 前端、后端(密码+加密盐+用户名)加密
  • 加密盐随登录随机生成

五、测试

修改

这里我只按照id查询, 但是后面自动添加了status=“0”是因为我们之前设置逻辑删除了,具体可以看图

网络异常,图片无法展示
|

mybatis-plus逻辑删除注解 @TableLogic

网络异常,图片无法展示
|

删除

同样的因为我们设置了mybatis-plus 的逻辑删除,那么删除的时候是默认把我们设置的逻辑删除字段改为“1”

网络异常,图片无法展示
|

六、总结

详情具体的查SQL直接写到了controller层了, 感觉不太对, 但是目前对于Controller, Service我感觉对其还是了解的不够彻底,如果有大佬希望可以在评论区留下一些自己的见解, 谢谢



目录
相关文章
|
12月前
|
存储 前端开发 PHP
构建一个简单的网站,包括用户注册、登录功能
构建一个简单的网站,包括用户注册、登录功能
217 1
|
4月前
|
前端开发 JavaScript 程序员
程序员必知:完成登录与注册页面的前端
程序员必知:完成登录与注册页面的前端
18 0
|
存储 数据安全/隐私保护 开发者
小白必看系列之图书管理系统-登录和注册功能示例代码
小白必看系列之图书管理系统-登录和注册功能示例代码
130 1
|
存储 缓存 小程序
微信开发之-登录
微信开发之-登录
100 0
|
安全 数据安全/隐私保护
WordPress建站教程:默认WordPress登录入口和修改后台入口
​今天关注六翼开源的一个网友遇到一个问题没办法突破,他在安装WordPress之后不知道WordPress后台登录入口,无法进入后台管理网站和更新文章。下面北京六翼的开发工程师针对“默认WordPress登录入口和修改后台入口”的问题给大家做一下讲解。
WordPress建站教程:默认WordPress登录入口和修改后台入口
|
存储 NoSQL Redis
博客项目(6、登录接口)
博客项目(6、登录接口)
74 0
|
数据安全/隐私保护 开发者 微服务
登录功能(接口问题解决) | 学习笔记
快速学习登录功能(接口问题解决)
登录功能(接口问题解决) | 学习笔记
|
弹性计算 Java 应用服务中间件
在阿里云ECS上搭建一个简单的具有登录和注册功能的网站
因为学校本学期开设了web的相关课程,为了加深对整个项目从编写到发布的理解,也感谢阿里云对学生的帮助与支持,让我得以白嫖一台ECS来学习。网站开发使用的是Mybatis+MySQL+Servlet+Tomcat,项目具体搭建方式参考https://blog.csdn.net/m0_59792745/article/details/126823742
147 0
在阿里云ECS上搭建一个简单的具有登录和注册功能的网站
|
XML 存储 Java
登录功能(接口) | 学习笔记
快速学习登录功能(接口)
|
数据安全/隐私保护 开发者 Python
登录功能的实现| 学习笔记
快速学习登录功能的实现