探索 Sa-Token (二) 登录认证、权限认证

(一)登录认证

  说明:因为这里没有连接数据,我模拟两个用户,用户:zhang ,用户:liu,密码 123456 提前做了加密。

1.密码加密接口

/**
     * 加密
     * @param pwd
     * @return
     */
    @GetMapping("/register")
    public SaResult register(String pwd) {
        // 注册用户
        String hashpw = BCrypt.hashpw(pwd);
        return SaResult.data(hashpw);
    }

2. 模拟数据库用户信息

 /**
     * 模拟数据库用户信息
     *
     * @param name
     * @return
     */
    private LoginUser builderLoginUser(String name) {
        String dbPwd = "$2a$10$roWr2BV2LcMrGFo2ST.vluO4DkwLVt5LhozZGP4OKz3.eh31lAJ6q";
        Set<String> perms = new HashSet<String>();
        LoginUser loginUser = new LoginUser();
        loginUser.setPwd(dbPwd);
        loginUser.setName(name);
        if ("zhang".equals(name)) {
            perms.add("*.*.*");
            loginUser.setId(10001);
            loginUser.setMenuPermission(perms);
        } else if ("liu".equals(name)){
            perms.add("web:test:user");
            loginUser.setId(10002);
            loginUser.setMenuPermission(perms);
        }
        return loginUser;
    }

3.登录接口

 /**
     * 登录
     *
     * @param name
     * @param pwd
     * @return
     */
    @GetMapping("/doLogin")
    public SaResult doLogin(String name, String pwd) {
        LoginUser loginUser = builderLoginUser(name);
        boolean checkpw = BCrypt.checkpw(pwd, loginUser.getPwd());
        // 第一步:比对前端提交的账号名称、密码
        if (checkpw) {
            // 第二步:根据账号id,进行登录,指定设备类型
            StpUtil.login(loginUser.getId(), DeviceType.PC.getDevice());
            StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser);
            return SaResult.data(StpUtil.getTokenInfo());
        }
        return SaResult.error("登录失败");
    }

这里为了做简单测试就不做其它等校验。

StpUtil.login(用户ID,设备类型)  

#test#result

 

 登录成功之后尝试,用token访问下其他接口

 登录认证成功。

(二)权限认证

所谓权限认证,核心逻辑就是判断一个账号是否拥有指定权限:

  • 有,就让你通过。
  • 没有?那么禁止访问!

深入到底层数据中,就是每个账号都会拥有一个权限码集合,框架来校验这个集合中是否包含指定的权限码。

例如:当前账号拥有权限码集合 ["user-add", "user-delete", "user-get"],这时候我来校验权限 "user-update",则其结果就是:验证失败,禁止访问

1. 自定义SaPermissionImpl 实现StpInterface 接口

@Component
public class SaPermissionImpl implements StpInterface {

    /**
     * 获取菜单权限列表
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 当用户调用权限验证的时候走
        LoginUser loginUser = getLoginUser();
        // 返回当前登录用户拥有的菜单集合
        return new ArrayList<>(loginUser.getMenuPermission());
    }

    private  LoginUser getLoginUser() {
        return  (LoginUser) StpUtil.getTokenSession().get(LOGIN_USER_KEY);
    }


    /**
     * 获取角色权限列表
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        return null;
    }
}

说明:前面模拟两个用户,zhang ,权限集合["*.*.*"] 表示超级管理员,啥接口都能访问,liu 是普通用户,权限集合["web:test:user"]

新建两个测试接口:

   @SaCheckPermission("web:test:user")
    @GetMapping("/getLoginUser")
    public SaResult getLoginUser() {
        Object loginId = StpUtil.getLoginId();
        System.out.println("接口[getLoginUser]当前用户:" + loginId);
        return SaResult.data(loginId);
    }


    @SaCheckPermission("web:test:testPerms")
    @GetMapping("/testPerms")
    public SaResult testPerms() {
        Object loginId = StpUtil.getLoginId();
        System.out.println("接口[testPerms]当前用户:" + loginId);
        return SaResult.data(loginId);
    }

可以看到用户liu是没有第二个接口的权限的。

#test#result

 用户zhang两个接口都这可以正常访问。

 用户liu没有第二个接口的权限,测试结果成功。

### 这里输出的log其实是做了全局异常的捕获。

#GlobalExceptionHandler

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.http.HttpStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * @author yueF_L
 * @version 1.0
 * @date 2022-09-07 11:20
 * 全局异常处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 认证失败
     */
    @ExceptionHandler(NotLoginException.class)
    public SaResult handleNotLoginException(NotLoginException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',认证失败'{}',无法访问系统资源", requestURI, e.getMessage());
        return SaResult.get(HttpStatus.HTTP_UNAUTHORIZED, "认证失败,无法访问系统资源", null);
    }

    /**
     * 权限码异常
     */
    @ExceptionHandler(NotPermissionException.class)
    public SaResult handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',权限码校验失败'{}'", requestURI, e.getMessage());
        return SaResult.get(HttpStatus.HTTP_FORBIDDEN, "没有访问权限,请联系管理员授权",null);
    }

}

猜你喜欢

转载自blog.csdn.net/weixin_38982591/article/details/126765804