[pig框架源码分析] 01 - 权限管理系统

pig白皮书介绍

权限管理实现

基于角色的访问控制方法(Role-Based Access Control,简称 RBAC)是目前公认的解决大型企业的统一资源访问控制的有效方法。其显著的两大特征是:

  1. 减小授权管理的复杂性,降低管理开销;
  2. 灵活地支持企业的安全策略,并对企业的变化有很大的伸缩性。

提供多租户用户-角色-部门-权限的权限管理模型,确保开发工程师拿来即用。
在这里插入图片描述

数据库关系

sys_user是关键表,从user入手,又分为两块:角色菜单和部门。

用户-角色-菜单,用户和角色是多对多的关系,角色和菜单也是多对多的关系。所以,有两个关系表sys_user_rolesys_role_menu。数据库中查询出所有信息,即可查到一个用户的多个角色,以及相应的菜单和权限。

用户-部门,用户和部门之间是多对一的关系(本系统是这样的),所以在用户表中包含dept_id即可,不需要独立的一张关系表。

在这里插入图片描述

接口统计

通过swagger,我们可以直观的查看出权限管理相关接口。

部门

在这里插入图片描述

用户

在这里插入图片描述

角色

在这里插入图片描述

菜单

在这里插入图片描述

登录

登录逻辑,涉及到授权、用户、权限等,我们这里主要分析后台的密码解密逻辑,下面是浏览器捕获的网络封包请求。
ps: 我们可以直接通过pig提供的在线体验网站进行分析

在这里插入图片描述

登录请求

POST http://localhost:8080/auth/oauth/token?randomStr=90971641286816619&code=1&grant_type=password&scope=server
username: admin
password: YehdBPev

在nacos后台,我们查看配置可以看到,/auth/**请求最后调用的是pig-auth服务,其中有过滤器PasswordDecoderFilter将前端密码解密。
在这里插入图片描述


	@Override
	public GatewayFilter apply(Object config) {
		return (exchange, chain) -> {
			ServerHttpRequest request = exchange.getRequest();
			// 1. 不是登录请求,直接向下执行
			if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL)) {
				return chain.filter(exchange);
			}

			// 2. 刷新token类型,直接向下执行
			String grantType = request.getQueryParams().getFirst("grant_type");
			if (StrUtil.equals(SecurityConstants.REFRESH_TOKEN, grantType)) {
				return chain.filter(exchange);
			}

			// 3. 前端加密密文解密逻辑
			Class inClass = String.class;
			Class outClass = String.class;
			ServerRequest serverRequest = ServerRequest.create(exchange, messageReaders);

			// 4. 解密生成新的报文
			Mono<?> modifiedBody = serverRequest.bodyToMono(inClass).flatMap(decryptAES());
			…………
			…………
}

pig网关将前端密码解密后,将请求转发给pig-auth服务,该服务基于Spring Security用户认证流程实现,调用堆栈如下:
在这里插入图片描述

用户信息

GET http://localhost:8080/admin/user/info

	@GetMapping(value = { "/info" })
	public R info() {
		String username = SecurityUtils.getUser().getUsername();
		SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));
		if (user == null) {
			return R.failed("获取当前用户信息失败");
		}
		UserInfo userInfo = userService.getUserInfo(user);
		UserInfoVO vo = new UserInfoVO();
		vo.setSysUser(userInfo.getSysUser());
		vo.setRoles(userInfo.getRoles());
		vo.setPermissions(userInfo.getPermissions());
		return R.ok(vo);
	}
	
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {
	@Override
	public UserInfo getUserInfo(SysUser sysUser) {
		UserInfo userInfo = new UserInfo();
		userInfo.setSysUser(sysUser);
		// 设置角色列表
		List<SysRole> roleList = sysRoleMapper.listRolesByUserId(sysUser.getUserId());
		userInfo.setRoleList(roleList);
		// 设置角色列表 (ID)
		List<Integer> roleIds = roleList.stream().map(SysRole::getRoleId).collect(Collectors.toList());
		userInfo.setRoles(ArrayUtil.toArray(roleIds, Integer.class));
		// 设置权限列表(menu.permission)
		Set<String> permissions = roleIds.stream().map(sysMenuService::findMenuByRoleId).flatMap(Collection::stream)
				.filter(m -> MenuTypeEnum.BUTTON.getType().equals(m.getType())).map(SysMenu::getPermission)
				.filter(StrUtil::isNotBlank).collect(Collectors.toSet());
		userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));

		return userInfo;
	}
}

在这里插入图片描述

导航菜单

GET http://localhost:8080/admin/menu?parentId=-1


	@GetMapping
	public R getUserMenu(Integer parentId) {
		// 获取符合条件的菜单
		Set<SysMenu> menuSet = SecurityUtils.getRoles().stream().map(sysMenuService::findMenuByRoleId)
				.flatMap(Collection::stream).collect(Collectors.toSet());
		return R.ok(sysMenuService.filterMenu(menuSet, parentId));
	}

在这里插入图片描述

参考资料

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

夜猫逐梦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值