(一)登录认证
说明:因为这里没有连接数据,我模拟两个用户,用户: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 {/*** 获取菜单权限列表*/@Overridepublic 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);}/*** 获取角色权限列表*/@Overridepublic 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);}}