密码加密与验证
首先再自定义一个异常吧,创建一个通用点的MapleCommonException.java
,后续都偷懒统一抛这个异常了
代码如下:
package com.maple.demo.config.exception; import com.maple.demo.config.bean.ErrorCode; /** * 通用异常,偷懒就抛出此异常吧 * * @author 笑小枫 * @date 2022/07/20 */ public class MapleCommonException extends MapleBaseException { public MapleCommonException(String code, String errorMsg) { super(code, errorMsg); } public MapleCommonException(ErrorCode code) { super(code); } public MapleCommonException(ErrorCode code, String errorMsg) { super(code, errorMsg); } }
密码加密就简单的使用md5加盐值吧,代码如下👇
package com.maple.demo.util; import com.maple.demo.config.bean.ErrorCode; import com.maple.demo.config.exception.MapleCommonException; import lombok.extern.slf4j.Slf4j; import org.springframework.util.DigestUtils; import org.springframework.util.StringUtils; /** * MD5撒盐加密 及MD5加密 * * @author 笑小枫 * @date 2022/7/20 */ @Slf4j public class Md5Util { private Md5Util() { } /** * 密码加密处理 * * @param password 密码明文 * @param salt 盐 * @return 加密后密文 */ public static String encrypt(String password, String salt) { if (StringUtils.isEmpty(password) || StringUtils.isEmpty(salt)) { log.error("密码加密失败原因: password and salt cannot be empty"); throw new MapleCommonException(ErrorCode.PARAM_ERROR); } return DigestUtils.md5DigestAsHex((salt + password).getBytes()); } /** * 校验密码 * * @param target 待校验密码 * @param source 原密码 * @param salt 加密原密码的盐 */ public static boolean verifyPassword(String target, String source, String salt) { if (StringUtils.isEmpty(target) || StringUtils.isEmpty(source) || StringUtils.isEmpty(salt)) { log.info("校验密码失败,原因 target ={}, source ={}, salt ={}", target, source, salt); return false; } String targetEncryptPwd = encrypt(target, salt); return targetEncryptPwd.equals(source); } public static void main(String[] args) { log.info(encrypt("admin111", "123456")); } }
通过main方法生成一个加密后的值吧,然后把盐值和密码都扔到数据库里面,后面我们就根据账号(account)和密码(password)进行登录。
注意:创建用户的时候先随机生成一个盐(salt),后续根据盐值再去生成密码。
用户登录接口
model和param
创建一个vo包吧,后续的model和query对象统一放在这里了~
在vo包下创建一个query包,然后创建登录请求对象LoginQuery.java
package com.maple.demo.vo.query; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; /** * @author 笑小枫 * @date 2022/7/20 */ @Data @ApiModel(value = "用户登录请求对象", description = "用户中心-用户登录请求对象") public class LoginQuery { @ApiModelProperty(value = "登录账号") private String account; @ApiModelProperty(value = "登录密码") private String password; }
在vo包下创建一个model包,然后创建返回的用户信息对象UserModel.java
package com.maple.demo.vo.model; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.RequiredArgsConstructor; /** * 用户中心-用户信息 * * @author 笑小枫 * @date 2022/7/20 */ @Data @Builder @RequiredArgsConstructor @AllArgsConstructor @ApiModel(value = "用户视图对象", description = "用户中心-用户信息") public class UserModel { @ApiModelProperty(value = "用户ID") private Long id; @ApiModelProperty(value = "用户账号") private String account; @ApiModelProperty(value = "用户姓名") private String userName; @ApiModelProperty(value = "用户昵称") private String nickName; @ApiModelProperty(value = "用户类型") private String userType; @ApiModelProperty(value = "用户邮箱") private String email; @ApiModelProperty(value = "手机号码") private String phone; @ApiModelProperty(value = "用户性别") private String sex; @ApiModelProperty(value = "头像地址") private String avatar; @ApiModelProperty(value = "帐号状态") private String status; @ApiModelProperty(value = "备注") private String remark; @ApiModelProperty(value = "用户验证Token") private String token; }
controller
package com.maple.demo.controller; import com.maple.demo.service.IUserService; import com.maple.demo.vo.model.UserModel; import com.maple.demo.vo.query.LoginQuery; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; /** * 系统登录 * * @author 笑小枫 * @date 2022/7/20 */ @Api(tags = "管理系统-系统登录操作") @RestController @AllArgsConstructor @RequestMapping(value = "/sso") public class LoginController { private final IUserService userService; @ApiOperation(value = "用户登录") @PostMapping("/login") public UserModel login(@RequestBody LoginQuery req) { return userService.login(req); } @ApiOperation(value = "用户退出登录") @GetMapping("/logout") public void logout() { userService.logout(); } }
service
package com.maple.demo.service; import com.baomidou.mybatisplus.extension.service.IService; import com.maple.demo.entity.User; import com.maple.demo.vo.model.UserModel; import com.maple.demo.vo.query.LoginQuery; /** * <p> * 用户中心-用户信息表 服务类 * </p> * * @author 笑小枫 * @since 2022-07-11 */ public interface IUserService extends IService<User> { /** * 用户登录 * * @param req 用户信息 * @return 用户登录信息 */ UserModel login(LoginQuery req); /** * 退出系统,清除用户token */ void logout(); }
serviceImpl
package com.maple.demo.service.impl; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.maple.demo.config.bean.ErrorCode; import com.maple.demo.config.bean.GlobalConfig; import com.maple.demo.config.bean.TokenBean; import com.maple.demo.config.exception.MapleCheckException; import com.maple.demo.entity.User; import com.maple.demo.mapper.UserMapper; import com.maple.demo.service.IUserService; import com.maple.demo.util.JwtUtil; import com.maple.demo.util.Md5Util; import com.maple.demo.util.RedisUtil; import com.maple.demo.vo.model.UserModel; import com.maple.demo.vo.query.LoginQuery; import lombok.AllArgsConstructor; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import java.util.Objects; /** * <p> * 用户中心-用户信息表 服务实现类 * </p> * * @author Maple * @since 2022-07-11 */ @Service @AllArgsConstructor public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService { private final UserMapper userMapper; private final RedisUtil redisUtil; @Override public UserModel login(LoginQuery req) { User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class) .eq(User::getAccount, req.getAccount()) .last("LIMIT 1")); if (Objects.isNull(user)) { throw new MapleCheckException(ErrorCode.USER_LOGIN_ERROR); } if ("1".equals(user.getStatus())) { throw new MapleCheckException(ErrorCode.USER_STATUS_ERROR); } if (!Md5Util.verifyPassword(req.getPassword(), user.getPassword(), user.getSalt())) { throw new MapleCheckException(ErrorCode.USER_LOGIN_ERROR); } TokenBean tokenBean = TokenBean.builder() .userId(user.getId()) .userType(user.getUserType()) .account(user.getUserName()) .build(); UserModel userModel = new UserModel(); BeanUtils.copyProperties(user, userModel); String token; try { token = JwtUtil.createToken(tokenBean); } catch (Exception e) { log.error(e.getMessage()); throw new MapleCheckException(ErrorCode.COMMON_ERROR); } userModel.setToken(token); redisUtil.set(GlobalConfig.getRedisUserKey(user.getAccount()), token); return userModel; } @Override public void logout() { redisUtil.remove(GlobalConfig.getRedisUserKey(JwtUtil.getAccount())); } }
使用JWT的用户信息
直接使用JwtUtil.class
工具类里的方法,即可拿到对应的数据
JwtUtil.getUserId(); JwtUtil.getAccount();
功能测试
测试之前需要在数据中添加一条数据
INSERT INTO `maple`.`usc_user`( `account`, `user_name`, `nick_name`, `user_type`, `email`, `phone`, `sex`, `avatar`, `salt`, `password`, `status`, `create_id`, `create_name`, `create_time`, `update_id`, `update_name`, `update_time`, `delete_flag`, `remark`) VALUES ('admin', 'admin', '笑小枫', '00', '1150640979@qq.com', '18300000001', '0', '', '123456', 'e9c764f9b51772f00af80a54d38a692e', '0', 1, '笑小枫', '2022-07-11 13:48:44', 1, '笑小枫', '2022-07-11 13:48:44', 0, '管理员');
直接在LoginController.java
里面添加getUserId
方法进行测试,详细代码如下:
package com.maple.demo.controller; import com.maple.demo.service.IUserService; import com.maple.demo.util.JwtUtil; import com.maple.demo.vo.model.UserModel; import com.maple.demo.vo.query.LoginQuery; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.*; /** * 系统登录 * * @author 笑小枫 * @date 2022/7/20 */ @Api(tags = "管理系统-系统登录操作") @RestController @AllArgsConstructor @RequestMapping(value = "/sso") public class LoginController { private final IUserService userService; @ApiOperation(value = "用户登录") @PostMapping("/login") public UserModel login(@RequestBody LoginQuery req) { return userService.login(req); } @ApiOperation(value = "用户退出登录") @GetMapping("/logout") public void logout() { userService.logout(); } @ApiOperation(value = "获取登录用户信息") @GetMapping("/getUserId") public String getUserId() { return "当前登录用户的ID为" + JwtUtil.getUserId(); } }
在未登录状态请求接口,返回信息如下:
调用登录接口,进行用户登录
登录后,拿到token,在请求头设置Authorization参数
添加完之后,记得要把tab页关闭,再打开,然后header参数才会生效,在请求头部可以看到
再次调用,返回信息如下:
可以看到,到此我们的登录拦截功能就已经完全实现了。
小结
好啦,本文就到这里了,我们简单的总结一下,主要介绍了以下内容👇👇
- 介绍了什么是JWT
- 用户登录拦截
- 用户登录实现
关于笑小枫💕
本章到这里结束了,喜欢的朋友关注一下我呦😘😘,大伙的支持,就是我坚持写下去的动力。
老规矩,懂了就点赞收藏;不懂就问,日常在线,我会就会回复哈~🤪
笑小枫个人博客:https://www.xiaoxiaofeng.com