Spring Boot 2.x + shiro前后端分离实战-实现用户登录认证访问授权 实战篇(十二)

登录接口业务

    @Override
    public LoginResVO login(LoginReqVO reqVO) {
        SysUser sysUser = sysUserMapper.getByUserName(reqVO.getUsername());
        if (null == sysUser) {
            throw new BusinessException(40001004, "用户不存在,请注册");
        }
        if (sysUser.getStatus() == 2) {
            throw new BusinessException(40001005, "该用户已禁用,请联系系统管理员");
        }
        if (!PasswordUtils.matches(sysUser.getSalt(), reqVO.getPassword(), sysUser.getPassword())) {
            throw new BusinessException(40001006, "密码不匹配,请重新登录");
        }
        LoginResVO loginResVO = new LoginResVO();
        loginResVO.setUserId(sysUser.getId());
        String token = UUID.randomUUID().toString();
        loginResVO.setToken(token);
        redis.set(token, sysUser.getId(), 60, TimeUnit.SECONDS);
        return loginResVO;
    }

密码工具

public class PasswordEncoder {

    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d",
            "e", "f"};

    private final static String MD5 = "MD5";
    private final static String SHA = "SHA";

    private Object salt;
    private String algorithm;

    public PasswordEncoder(Object salt) {
        this(salt, MD5);
    }

    public PasswordEncoder(Object salt, String algorithm) {
        this.salt = salt;
        this.algorithm = algorithm;
    }

    /**
     * 密码加密
     *
     * @param rawPass
     * @return
     */
    public String encode(String rawPass) {
        String result = null;
        try {
            MessageDigest md = MessageDigest.getInstance(algorithm);
            // 加密后的字符串
            result = byteArrayToHexString(md.digest(mergePasswordAndSalt(rawPass).getBytes("utf-8")));
        } catch (Exception ex) {
        }
        return result;
    }

    /**
     * 密码匹配验证
     *
     * @param encPass 密文
     * @param rawPass 明文
     * @return
     */
    public boolean matches(String encPass, String rawPass) {
        String pass1 = "" + encPass;
        String pass2 = encode(rawPass);

        return pass1.equals(pass2);
    }

    private String mergePasswordAndSalt(String password) {
        if (password == null) {
            password = "";
        }

        if ((salt == null) || "".equals(salt)) {
            return password;
        } else {
            return password + "{" + salt.toString() + "}";
        }
    }

    /**
     * 转换字节数组为16进制字串
     *
     * @param b 字节数组
     * @return 16进制字串
     */
    private String byteArrayToHexString(byte[] b) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }

    /**
     * 将字节转换为16进制
     *
     * @param b
     * @return
     */
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n = 256 + n;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }

    public static void main(String[] args) {

    }


}```

```java
public class PasswordUtils {

    /**
     * 匹配密码
     *
     * @param salt    盐
     * @param rawPass 明文
     * @param encPass 密文
     * @return
     */
    public static boolean matches(String salt, String rawPass, String encPass) {
        return new PasswordEncoder(salt).matches(encPass, rawPass);
    }

    /**
     * 明文密码加密
     *
     * @param rawPass 明文
     * @param salt
     * @return
     */
    public static String encode(String rawPass, String salt) {
        return new PasswordEncoder(salt).encode(rawPass);
    }

    /**
     * 获取加密盐
     *
     * @return
     */
    public static String getSalt() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 20);
    }
}

用户详情业务

@Override
    public SysUser detail(String id) {
        return sysUserMapper.selectByPrimaryKey(id);
    }

RESTful 控制层接口

@RestController
@RequestMapping("/api")
@Api(tags = "用户模块", description = "用户模块相关接口")
public class UserController {
    @Autowired
    private IUserService userService;

    @ApiOperation(value = "用户登录接口")
    @PostMapping("/user/login")
    public Map<String, Object> login(@RequestBody LoginReqVO vo) {
        Map<String, Object> map = new HashMap<>();
        map.put("code", 0);
        map.put("data", userService.login(vo));
        return map;
    }

    @ApiOperation(value = "根据用户ID查询人员信息")
    @GetMapping("/user/{id}")
    @RequiresPermissions("sys:user:detail")
    public Map<String, Object> detail(@PathVariable("id") String id) {
        Map<String, Object> map = new HashMap<>();
        map.put("code", 0);
        map.put("data", userService.detail(id));
        return map;
    }
}

配置登录接口白名单

ShiroConfigshiroFilterFactoryBean加入shiro 忽略拦截

  filterChainDefinitionMap.put("/api/user/login", "anon");

接口业务分析

登录接口

  1. 用 LoginReqVO 接收用户提交过来的用户名密码的数据
  2. 把 vo 传入业务层接口进行业务处理
  3. 登录业务处理
    a. 通过用户名去db查询用户信息
    b. 判断是否查询到用信息
    c. 判断是否被禁用
    d. 校验密码是否正确
    e. 生成token、把token做为key、userId作为value存入redis并设置过期时间为60分钟(后面认证需要)
    f. 封装返回数据LoginRespVO 返回前端

获取用户详情接口

这个接口有两个关键点,因为用户首次登录后,后续再访问我们的系统资源的时候,无需再传入用户密码进行验证只需要携带登录生成的token可以了,我们的后端会围绕token使用shiro进行一系列的认证。当用户通过了用户认证的时候还需要进行授权,因为用户详解接口设置了访问权限(@RequiresPermissions(“sys:user:detail”))所以我们还要对访问的用户进行授权。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一名技术极客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值