springBoot项目搭建包含RBAC模块 -- 用户登录开发(九)

上一章我们讲了用户管理模块开发,到此我们的rbac模块 资源管理、角色管理、用户管理都已开发完。这一章我们开发用户登录模块,基于用户名和密码登录,鉴权我们用的是token,使用的是redis来管理token。

1.创建工程目录

用户登录功能在server工程下开发,创建controller、filter、pojo、service、startup工程目录

2. 获取token

登录我分了两步去做的,首先去获取初始化一个随机token,token用于给用户鉴权。初始化的token状态是false,只有登录成功以后token状态会变成true。缓存在redis中过期时间默认给的是30分钟。

创建一个UserLoginController 

package com.swh.server.controller;

import com.swh.admin.pojo.resp.RespAdminUserInfo;
import com.swh.common.result.AjaxResult;
import com.swh.common.utils.JackJsonUtil;
import com.swh.server.pojo.req.ReqLocalUserLoginVo;
import com.swh.server.service.UserLoginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import static com.swh.common.constant.CommonConst.NotInterceptUrl.ADMIN_USER_LOGIN;
import static com.swh.common.constant.CommonConst.NotInterceptUrl.GENERATE_KEY;
import static com.swh.common.constant.CommonConst.SWH_TOKEN;

/**
 * @ClassName: UserLoginController
 * @Description:
 * @Author: songWenHao
 * @Date: 2022/6/17 9:33
 */
@Slf4j
@Api(tags = "登录")
@RestController
public class UserLoginController {

    @Autowired
    private UserLoginService userLoginService;

    @ApiOperation(value = "获取token,用-分割,最后一节是用于加密的AES密钥")
    @GetMapping(GENERATE_KEY)
    public AjaxResult<String> getAesKey(@RequestHeader(value = SWH_TOKEN, required = false) String token) {
        return AjaxResult.ok(userLoginService.getAesKey(token));
    }

}

创建一个UserLoginService

package com.swh.server.service;

import com.swh.admin.pojo.resp.RespAdminUserInfo;
import com.swh.server.pojo.req.ReqLocalUserLoginVo;

/**
 * @ClassName: UserLoginService
 * @Description:
 * @Author: songWenHao
 * @Date: 2022/6/17 9:35
 */
public interface UserLoginService {

    /**
     * 获取token
     *
     * @param token
     * @return
     */
    String getAesKey(String token);
}

创建一个UserLoginServiceImpl,实现生成token的具体逻辑

package com.swh.server.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import com.swh.admin.dao.AdminResDao;
import com.swh.admin.dao.AdminUserDao;
import com.swh.admin.dao.RoleResMpDao;
import com.swh.admin.dao.UserRoleMpDao;
import com.swh.admin.pojo.db.DbAdminResVo;
import com.swh.admin.pojo.db.DbAdminUserVo;
import com.swh.admin.pojo.resp.RespAdminResTreeVo;
import com.swh.admin.pojo.resp.RespAdminUserInfo;
import com.swh.admin.service.AdminResService;
import com.swh.common.exception.RequestException;
import com.swh.common.utils.*;
import com.swh.server.pojo.req.ReqLocalUserLoginVo;
import com.swh.server.service.UserLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.swh.common.constant.AdminUserConst.MenuLevle.LEVLE_THREE;
import static com.swh.common.constant.CommonConst.*;
import static com.swh.common.constant.CommonConst.CacheKey.REDIS_ADMIN_USER_LOGIN;
import static com.swh.common.result.ResultCode.USERNAME_OR_PASSWORD_INVALID;

/**
 * @ClassName: UserLoginServiceImpl
 * @Description:
 * @Author: songWenHao
 * @Date: 2022/6/17 9:35
 */
@Slf4j
@Service
public class UserLoginServiceImpl implements UserLoginService {


    @Override
    public String getAesKey(String t) {
        if (StrUtil.isBlank(t)) {
            String key = RandomUtil.randomString(16);
            LOGGER.debug("首次访问获取的AES key:{}", key);
            String token = "swh-" + DbIdUtil.getInstance().nextUuid() + "-" + key;
            redisCacheUtil.hashPut(token, LOGIN_STATUS, "false", SESSION_TIME, TimeUnit.MINUTES);
            return token;
        } else {
            return t;
        }
    }

}

2. 本地登录

登录逻辑主要分为 ①:校验用户是否存在;②:验证用户密码;③:验证成功以后组装用户返回信息和处理redis中缓存的token信息。

在UserLoginController写登录接口:

package com.swh.server.controller;

import com.swh.admin.pojo.resp.RespAdminUserInfo;
import com.swh.common.result.AjaxResult;
import com.swh.common.utils.JackJsonUtil;
import com.swh.server.pojo.req.ReqLocalUserLoginVo;
import com.swh.server.service.UserLoginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import static com.swh.common.constant.CommonConst.NotInterceptUrl.ADMIN_USER_LOGIN;
import static com.swh.common.constant.CommonConst.NotInterceptUrl.GENERATE_KEY;
import static com.swh.common.constant.CommonConst.SWH_TOKEN;

/**
 * @ClassName: UserLoginController
 * @Description:
 * @Author: songWenHao
 * @Date: 2022/6/17 9:33
 */
@Slf4j
@Api(tags = "登录")
@RestController
public class UserLoginController {

    @Autowired
    private UserLoginService userLoginService;

    @ApiOperation(value = "获取token,用-分割,最后一节是用于加密的AES密钥")
    @GetMapping(GENERATE_KEY)
    public AjaxResult<String> getAesKey(@RequestHeader(value = SWH_TOKEN, required = false) String token) {
        return AjaxResult.ok(userLoginService.getAesKey(token));
    }

    @ApiOperation("本地登录")
    @PostMapping(ADMIN_USER_LOGIN)
    public AjaxResult<RespAdminUserInfo> localUserLogin(@RequestBody ReqLocalUserLoginVo req, @RequestHeader(SWH_TOKEN) String token) {
        LOGGER.info("本地登录,参数:{},token:{}", JackJsonUtil.obj2String(req), token);
        return AjaxResult.ok(userLoginService.localUserLogin(req, token));
    }
}

登录的具体实现逻辑:

UserLoginService

package com.swh.server.service;

import com.swh.admin.pojo.resp.RespAdminUserInfo;
import com.swh.server.pojo.req.ReqLocalUserLoginVo;

/**
 * @ClassName: UserLoginService
 * @Description:
 * @Author: songWenHao
 * @Date: 2022/6/17 9:35
 */
public interface UserLoginService {

    /**
     * 获取token
     *
     * @param token
     * @return
     */
    String getAesKey(String token);

    /**
     * 本地登录
     *
     * @param req
     * @param token
     * @return
     */
    RespAdminUserInfo localUserLogin(ReqLocalUserLoginVo req, String token);
}

UserLoginServiceImpl

package com.swh.server.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import com.swh.admin.dao.AdminResDao;
import com.swh.admin.dao.AdminUserDao;
import com.swh.admin.dao.RoleResMpDao;
import com.swh.admin.dao.UserRoleMpDao;
import com.swh.admin.pojo.db.DbAdminResVo;
import com.swh.admin.pojo.db.DbAdminUserVo;
import com.swh.admin.pojo.resp.RespAdminResTreeVo;
import com.swh.admin.pojo.resp.RespAdminUserInfo;
import com.swh.admin.service.AdminResService;
import com.swh.common.exception.RequestException;
import com.swh.common.utils.*;
import com.swh.server.pojo.req.ReqLocalUserLoginVo;
import com.swh.server.service.UserLoginService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.swh.common.constant.AdminUserConst.MenuLevle.LEVLE_THREE;
import static com.swh.common.constant.CommonConst.*;
import static com.swh.common.constant.CommonConst.CacheKey.REDIS_ADMIN_USER_LOGIN;
import static com.swh.common.result.ResultCode.USERNAME_OR_PASSWORD_INVALID;

/**
 * @ClassName: UserLoginServiceImpl
 * @Description:
 * @Author: songWenHao
 * @Date: 2022/6/17 9:35
 */
@Slf4j
@Service
public class UserLoginServiceImpl implements UserLoginService {

    @Autowired
    private AdminUserDao adminUserDao;
    @Autowired
    private UserRoleMpDao userRoleMpDao;
    @Autowired
    private RoleResMpDao roleResMpDao;
    @Autowired
    private AdminResDao adminResDao;
    @Autowired
    private RedisCacheUtil redisCacheUtil;
    @Autowired
    private AdminResService adminResService;


    @Override
    public String getAesKey(String t) {
        if (StrUtil.isBlank(t)) {
            String key = RandomUtil.randomString(16);
            LOGGER.debug("首次访问获取的AES key:{}", key);
            String token = "swh-" + DbIdUtil.getInstance().nextUuid() + "-" + key;
            redisCacheUtil.hashPut(token, LOGIN_STATUS, "false", SESSION_TIME, TimeUnit.MINUTES);
            return token;
        } else {
            return t;
        }
    }


    @Override
    public RespAdminUserInfo localUserLogin(ReqLocalUserLoginVo req, String token) {

        //验证用户名
        DbAdminUserVo userVo = adminUserDao.getAdminUserByAccount(req.getAccount());
        if (ObjectUtil.isNull(userVo)) {
            throw new RequestException(USERNAME_OR_PASSWORD_INVALID);
        }

        //验证密码
        String tmpPassword = SmUtil.sm3(req.getAccount() + DecryptPasswordUtil.e(req.getPassword()));
        if (!StrUtil.equals(tmpPassword, userVo.getPassword())) {
            throw new RequestException(USERNAME_OR_PASSWORD_INVALID);
        }
        return build(userVo, token);
    }

    /**
     * 构建用户信息返回前端
     *
     * @param dbAdminUserVo
     * @param token
     * @return
     */
    private RespAdminUserInfo build(DbAdminUserVo dbAdminUserVo, String token) {

        //组装用户信息需要放置的信息
        Map<String, String> mapLoginUserMap = MapUtil.newHashMap(5);
        //获取用户关联的角色ID
        List<String> listRoleIds = userRoleMpDao.getRoleIdsByUserId(dbAdminUserVo.getId());
        // 根据角色获取关联的资源Id
        List<String> listResIds = roleResMpDao.getResIdsByRoleIds(listRoleIds);
        //根据资源Id获取所有的资源
        List<DbAdminResVo> resultRes = adminResDao.getResourceByIds(listResIds);
        //可访问的path 路径
        List<String> resPath = resultRes.parallelStream().map(r -> {
            if (ObjectUtil.isNotNull(r) && r.getLevel() == LEVLE_THREE) {
                return r.getPath();
            }
            return null;
        }).filter(Objects::nonNull).distinct().collect(Collectors.toList());

        //可访问的资源ID
        List<String> resCode = resultRes.parallelStream().map(r -> {
            if (ObjectUtil.isNotNull(r) && r.getLevel() == LEVLE_THREE) {
                return r.getModelCode() + r.getFunCode() + r.getOperCode();
            }
            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        //生成用户菜单
        List<RespAdminResTreeVo> menu = adminResService.getUserMenuTree(resultRes);

        //组装用户信息需要放置的信息
        mapLoginUserMap.put(LOGIN_STATUS, "true");
        mapLoginUserMap.put(ADMIN_RES_PATH, JackJsonUtil.obj2String(resPath));
        mapLoginUserMap.put(ADMIN_USER_ID, dbAdminUserVo.getId());
        mapLoginUserMap.put(ADMIN_USER_NAME, UrlUtil.encode(dbAdminUserVo.getUserName()));
        mapLoginUserMap.put(ADMIN_USER_ACCOUNT, dbAdminUserVo.getAccount());
        redisCacheUtil.hashPut(token, mapLoginUserMap, 30, TimeUnit.MINUTES);
        return new RespAdminUserInfo(dbAdminUserVo, resCode, menu);
    }
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值