✨ Introducing new features. 新增角色管理和app登录

1. 完成角色管理
2. 完成菜单管理
3. 完成app用户登录,使用app的用户信息
This commit is contained in:
aeizzz committed 2022-12-08 15:52:06 +08:00
1 parent 669b20cf82
commit 986bb47b07
22 files changed
+661 -73

No files matched your search

@@ -0,0 +1,55 @@
/*
*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*
*/
package com.pig4cloud.pigx.app.api.dto;
import com.pig4cloud.pigx.app.api.entity.AppUser;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* @author lengleng
* @date 2017/11/11
*/
@Data
@ApiModel(value = "用户信息")
public class AppUserInfo implements Serializable {
/**
* 用户基本信息
*/
@ApiModelProperty(value = "用户基本信息")
private AppUser appUser;
/**
* 权限标识集合
*/
@ApiModelProperty(value = "权限标识集合")
private String[] permissions;
/**
* 角色集合
*/
@ApiModelProperty(value = "角色标识集合")
private Long[] roles;
}
@@ -0,0 +1,70 @@
/*
*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*
*/
package com.pig4cloud.pigx.app.api.feign;
import com.pig4cloud.pigx.app.api.dto.AppUserInfo;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.constant.ServiceNameConstants;
import com.pig4cloud.pigx.common.core.util.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestHeader;
/**
* @author lengleng
* @date 2018/6/22
*/
@FeignClient(contextId = "remoteAppUserService", value = ServiceNameConstants.APP_SERVER)
public interface RemoteAppUserService {
/**
* 通过用户名查询用户、角色信息
*
* @param username 用户名
* @param from 调用标志
* @return R
*/
@GetMapping("/appuser/info/{username}")
R<AppUserInfo> info(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM) String from);
// /**
// * 通过社交账号或手机号查询用户、角色信息
// * @param inStr appid@code
// * @param from 调用标志
// * @return
// */
// @GetMapping("/social/info/{inStr}")
// R<AppUserInfo> social(@PathVariable("inStr") String inStr, @RequestHeader(SecurityConstants.FROM) String from);
//
/**
* 锁定用户
*
* @param username 用户名
* @param from 调用标识
* @return
*/
@PutMapping("/user/lock/{username}")
R<Boolean> lockUser(@PathVariable("username") String username, @RequestHeader(SecurityConstants.FROM) String from);
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2025, lengleng All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the pig4cloud.com developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: lengleng (wangiegie@gmail.com)
*/
package com.pig4cloud.pigx.app.api.vo;
import io.swagger.annotations.ApiModel;
import lombok.Data;
/**
* @author lengleng
* @date 2020/2/10
*/
@Data
@ApiModel(value = "前端角色展示对象")
public class AppRoleVO {
/**
* 角色id
*/
private Long roleId;
/**
* 菜单列表
*/
private String menuIds;
}
@@ -19,10 +19,12 @@ package com.pig4cloud.pigx.app.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.admin.api.entity.SysMenu;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.app.api.entity.AppMenu;
import com.pig4cloud.pigx.app.service.AppMenuService;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
import io.swagger.annotations.Api;
@@ -30,7 +32,11 @@ import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 菜单权限表
@@ -47,79 +53,87 @@ public class AppMenuController {
private final AppMenuService appMenuService;
/**
* 分页查询
* @param page 分页对象
* @param appMenu 菜单权限表
* @return
* 返回当前用户的树形菜单集合
* @param type 类型
* @param parentId 父节点ID
* @return 当前用户的树形菜单
*/
@ApiOperation(value = "分页查询", notes = "分页查询")
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('app_appmenu_view')")
public R getAppMenuPage(Page page, AppMenu appMenu) {
return R.ok(appMenuService.page(page, Wrappers.query(appMenu)));
@GetMapping
public R getUserMenu(String type, Long parentId) {
// 获取符合条件的菜单
Set<AppMenu> all = new HashSet<>();
SecurityUtils.getRoles().forEach(roleId -> all.addAll(appMenuService.findMenuByRoleId(roleId)));
return R.ok(appMenuService.filterMenu(all, type, parentId));
}
/**
* 通过id查询菜单权限表
* @param menuId id
* @return R
* 返回全部树形菜单集合
* @param parentId 父节点ID
* @param menuName 菜单名称
* @return 树形菜单
*/
@ApiOperation(value = "通过id查询", notes = "通过id查询")
@GetMapping("/{menuId}")
@PreAuthorize("@pms.hasPermission('app_appmenu_view')")
public R getById(@PathVariable("menuId") Long menuId) {
return R.ok(appMenuService.getById(menuId));
@GetMapping(value = "/tree")
public R getTree(Long parentId, String menuName) {
return R.ok(appMenuService.treeMenu(parentId, menuName));
}
/**
* 新增菜单权限表
* @param appMenu 菜单权限表
* @return R
* 返回角色的菜单集合授权
* @param roleId 角色ID
* @return 属性集合
*/
@ApiOperation(value = "新增菜单权限表", notes = "新增菜单权限表")
@SysLog("新增菜单权限表")
@GetMapping("/tree/{roleId}")
public R getRoleTree(@PathVariable Long roleId) {
return R.ok(
appMenuService.findMenuByRoleId(roleId).stream().map(AppMenu::getMenuId).collect(Collectors.toList()));
}
/**
* 通过ID查询菜单的详细信息
* @param id 菜单ID
* @return 菜单详细信息
*/
@GetMapping("/{id}")
public R getById(@PathVariable Long id) {
return R.ok(appMenuService.getById(id));
}
/**
* 新增菜单
* @param appMenu 菜单信息
* @return success/false
*/
@SysLog("新增菜单")
@PostMapping
@PreAuthorize("@pms.hasPermission('app_appmenu_add')")
public R save(@RequestBody AppMenu appMenu) {
return R.ok(appMenuService.save(appMenu));
public R save(@Valid @RequestBody AppMenu appMenu) {
appMenuService.save(appMenu);
return R.ok(appMenu);
}
/**
* 修改菜单权限表
* @param appMenu 菜单权限表
* @return R
* 删除菜单
* @param id 菜单ID
* @return success/false
*/
@ApiOperation(value = "修改菜单权限表", notes = "修改菜单权限表")
@SysLog("修改菜单权限表")
@SysLog("删除菜单")
@DeleteMapping("/{id}")
@PreAuthorize("@pms.hasPermission('app_appmenu_del')")
public R removeById(@PathVariable Long id) {
return appMenuService.removeMenuById(id);
}
/**
* 更新菜单
* @param appMenu
* @return
*/
@SysLog("更新菜单")
@PutMapping
@PreAuthorize("@pms.hasPermission('app_appmenu_edit')")
public R updateById(@RequestBody AppMenu appMenu) {
return R.ok(appMenuService.updateById(appMenu));
}
/**
* 通过id删除菜单权限表
* @param menuId id
* @return R
*/
@ApiOperation(value = "通过id删除菜单权限表", notes = "通过id删除菜单权限表")
@SysLog("通过id删除菜单权限表")
@DeleteMapping("/{menuId}")
@PreAuthorize("@pms.hasPermission('app_appmenu_del')")
public R removeById(@PathVariable Long menuId) {
return R.ok(appMenuService.removeById(menuId));
}
/**
* 导出excel 表格
* @param appMenu 查询条件
* @return excel 文件流
*/
@ResponseExcel
@GetMapping("/export")
@PreAuthorize("@pms.hasPermission('app_appmenu_export')")
public List<AppMenu> export(AppMenu appMenu) {
return appMenuService.list(Wrappers.query(appMenu));
public R update(@Valid @RequestBody AppMenu appMenu) {
return R.ok(appMenuService.updateMenuById(appMenu));
}
}
@@ -19,6 +19,8 @@ package com.pig4cloud.pigx.app.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.admin.api.vo.RoleVO;
import com.pig4cloud.pigx.app.api.vo.AppRoleVO;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.app.api.entity.AppRole;
@@ -54,7 +56,6 @@ public class AppRoleController {
*/
@ApiOperation(value = "分页查询", notes = "分页查询")
@GetMapping("/page")
@PreAuthorize("@pms.hasPermission('app_approle_view')")
public R getAppRolePage(Page page, AppRole appRole) {
return R.ok(appRoleService.page(page, Wrappers.query(appRole)));
}
@@ -120,6 +121,18 @@ public class AppRoleController {
return R.ok(appRoleService.removeById(roleId));
}
/**
* 更新角色菜单
* @param roleVo 角色对象
* @return success、false
*/
@SysLog("更新角色菜单")
@PutMapping("/menu")
@PreAuthorize("@pms.hasPermission('app_approle_perm')")
public R saveRoleMenus(@RequestBody AppRoleVO roleVo) {
return R.ok(appRoleService.updateRoleMenus(roleVo));
}
/**
* 导出excel 表格
* @param appRole 查询条件
@@ -17,13 +17,19 @@
package com.pig4cloud.pigx.app.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.admin.api.entity.SysUser;
import com.pig4cloud.pigx.app.api.dto.AppUserDTO;
import com.pig4cloud.pigx.app.api.vo.AppUserExcelVO;
import com.pig4cloud.pigx.common.core.exception.ErrorCodes;
import com.pig4cloud.pigx.common.core.util.MsgUtils;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.app.api.entity.AppUser;
import com.pig4cloud.pigx.app.service.AppUserService;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
import io.swagger.annotations.Api;
@@ -47,6 +53,31 @@ public class AppUserController {
private final AppUserService appUserService;
@Inner
@GetMapping("/info/{username}")
public R info(@PathVariable String username) {
AppUser user = appUserService.getOne(Wrappers.<AppUser>query().lambda().eq(AppUser::getUsername, username));
if (user == null) {
return R.failed(MsgUtils.getMessage(ErrorCodes.APP_USER_USERINFO_EMPTY, username));
}
return R.ok(appUserService.findUserInfo(user));
}
/**
* 获取当前用户全部信息
* @return 用户信息
*/
@GetMapping(value = { "/info" })
public R info() {
String username = SecurityUtils.getUser().getUsername();
AppUser user = appUserService.getOne(Wrappers.<AppUser>query().lambda().eq(AppUser::getUsername, username));
if (user == null) {
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));
}
return R.ok(appUserService.findUserInfo(user));
}
/**
* 分页查询
* @param page 分页对象
@@ -21,6 +21,8 @@ import com.pig4cloud.pigx.common.data.datascope.PigxBaseMapper;
import com.pig4cloud.pigx.app.api.entity.AppMenu;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* 菜单权限表
*
@@ -30,4 +32,5 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AppMenuMapper extends PigxBaseMapper<AppMenu> {
List<AppMenu> listMenusByRoleId(Long roleId);
}
@@ -17,8 +17,14 @@
package com.pig4cloud.pigx.app.service;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pig4cloud.pigx.admin.api.entity.SysMenu;
import com.pig4cloud.pigx.app.api.entity.AppMenu;
import com.pig4cloud.pigx.common.core.util.R;
import java.util.List;
import java.util.Set;
/**
* 菜单权限表
@@ -28,4 +34,43 @@ import com.pig4cloud.pigx.app.api.entity.AppMenu;
*/
public interface AppMenuService extends IService<AppMenu> {
/**
* 通过角色编号查询URL 权限
* @param roleId 角色ID
* @return 菜单列表
*/
List<AppMenu> findMenuByRoleId(Long roleId);
/**
* 级联删除菜单
* @param id 菜单ID
* @return 成功、失败
*/
R removeMenuById(Long id);
/**
* 更新菜单信息
* @param appMenu 菜单信息
* @return 成功、失败
*/
Boolean updateMenuById(AppMenu appMenu);
/**
* 构建树
* @param parentId 父节点ID
* @param menuName 菜单名称
* @return
*/
List<Tree<Long>> treeMenu(Long parentId, String menuName);
/**
* 查询菜单
* @param voSet
* @param parentId
* @return
*/
List<Tree<Long>> filterMenu(Set<AppMenu> voSet, String type, Long parentId);
}
@@ -28,4 +28,5 @@ import com.pig4cloud.pigx.app.api.entity.AppRoleMenu;
*/
public interface AppRoleMenuService extends IService<AppRoleMenu> {
Boolean saveRoleMenus(Long roleId, String menuIds);
}
@@ -19,6 +19,10 @@ package com.pig4cloud.pigx.app.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pig4cloud.pigx.app.api.entity.AppRole;
import com.pig4cloud.pigx.app.api.vo.AppRoleVO;
import java.util.Arrays;
import java.util.List;
/**
* app角色表
@@ -28,4 +32,7 @@ import com.pig4cloud.pigx.app.api.entity.AppRole;
*/
public interface AppRoleService extends IService<AppRole> {
Boolean updateRoleMenus(AppRoleVO roleVo);
List<AppRole> findRolesByUserId(Long userId);
}
@@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pig4cloud.pigx.app.api.dto.AppUserDTO;
import com.pig4cloud.pigx.app.api.dto.AppUserInfo;
import com.pig4cloud.pigx.app.api.entity.AppUser;
import com.pig4cloud.pigx.app.api.vo.AppUserExcelVO;
@@ -44,4 +45,5 @@ public interface AppUserService extends IService<AppUser> {
Boolean deleteUserById(Long userId);
AppUserInfo findUserInfo(AppUser user);
}
@@ -16,11 +16,41 @@
*/
package com.pig4cloud.pigx.app.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.admin.api.entity.SysMenu;
import com.pig4cloud.pigx.admin.api.entity.SysRoleMenu;
import com.pig4cloud.pigx.app.api.entity.AppMenu;
import com.pig4cloud.pigx.app.api.entity.AppRoleMenu;
import com.pig4cloud.pigx.app.mapper.AppMenuMapper;
import com.pig4cloud.pigx.app.mapper.AppRoleMenuMapper;
import com.pig4cloud.pigx.app.service.AppMenuService;
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
import com.pig4cloud.pigx.common.core.constant.enums.MenuTypeEnum;
import com.pig4cloud.pigx.common.core.exception.ErrorCodes;
import com.pig4cloud.pigx.common.core.util.MsgUtils;
import com.pig4cloud.pigx.common.core.util.R;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.validation.constraints.NotNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* 菜单权限表
@@ -29,6 +59,114 @@ import org.springframework.stereotype.Service;
* @date 2022-12-07 09:52:03
*/
@Service
@AllArgsConstructor
public class AppMenuServiceImpl extends ServiceImpl<AppMenuMapper, AppMenu> implements AppMenuService {
private final AppRoleMenuMapper appRoleMenuMapper;
@Override
public List<AppMenu> findMenuByRoleId(Long roleId) {
return baseMapper.listMenusByRoleId(roleId);
}
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = CacheConstants.MENU_DETAILS, allEntries = true)
public R removeMenuById(Long id) {
// 查询父节点为当前节点的节点
List<AppMenu> menuList = this.list(Wrappers.<AppMenu>query().lambda().eq(AppMenu::getParentId, id));
if (CollUtil.isNotEmpty(menuList)) {
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_MENU_DELETE_EXISTING));
}
appRoleMenuMapper.delete(Wrappers.<AppRoleMenu>query().lambda().eq(AppRoleMenu::getMenuId, id));
// 删除当前菜单及其子菜单
return R.ok(this.removeById(id));
}
@Override
public Boolean updateMenuById(AppMenu appMenu) {
return this.updateById(appMenu);
}
/**
* 构建树查询 1. 不是懒加载情况,查询全部 2. 是懒加载,根据parentId 查询 2.1 父节点为空,则查询ID -1
* @param parentId 父节点ID
* @param menuName 菜单名称
* @return
*/
@Override
public List<Tree<Long>> treeMenu(Long parentId, String menuName) {
Long parent = parentId == null ? CommonConstants.MENU_TREE_ROOT_ID : parentId;
List<TreeNode<Long>> collect = baseMapper
.selectList(
Wrappers.<AppMenu>lambdaQuery().like(StrUtil.isNotBlank(menuName), AppMenu::getName, menuName)
.orderByAsc(AppMenu::getSortOrder))
.stream().map(getNodeFunction()).collect(Collectors.toList());
// 模糊查询 不组装树结构 直接返回 表格方便编辑
if (StrUtil.isNotBlank(menuName)) {
return collect.stream().map(node -> {
Tree<Long> tree = new Tree<>();
tree.putAll(node.getExtra());
BeanUtils.copyProperties(node, tree);
return tree;
}).collect(Collectors.toList());
}
return TreeUtil.build(collect, parent);
}
/**
* 查询菜单
* @param all 全部菜单
* @param type 类型
* @param parentId 父节点ID
* @return
*/
@Override
public List<Tree<Long>> filterMenu(Set<AppMenu> all, String type, Long parentId) {
List<TreeNode<Long>> collect = all.stream().filter(menuTypePredicate(type)).map(getNodeFunction())
.collect(Collectors.toList());
Long parent = parentId == null ? CommonConstants.MENU_TREE_ROOT_ID : parentId;
return TreeUtil.build(collect, parent);
}
@NotNull
private Function<AppMenu, TreeNode<Long>> getNodeFunction() {
return menu -> {
TreeNode<Long> node = new TreeNode<>();
node.setId(menu.getMenuId());
node.setName(menu.getName());
node.setParentId(menu.getParentId());
node.setWeight(menu.getSortOrder());
// 扩展属性
Map<String, Object> extra = new HashMap<>();
extra.put("path", menu.getPath());
extra.put("menuType", menu.getMenuType());
extra.put("permission", menu.getPermission());
extra.put("label", menu.getName());
extra.put("sortOrder", menu.getSortOrder());
extra.put("visible", menu.getVisible());
node.setExtra(extra);
return node;
};
}
/**
* menu 类型断言
* @param type 类型
* @return Predicate
*/
private Predicate<AppMenu> menuTypePredicate(String type) {
return vo -> {
if (MenuTypeEnum.TOP_MENU.getDescription().equals(type)) {
return MenuTypeEnum.TOP_MENU.getType().equals(vo.getMenuType());
}
// 其他查询 左侧 + 顶部
return !MenuTypeEnum.BUTTON.getType().equals(vo.getMenuType());
};
}
}
@@ -16,12 +16,20 @@
*/
package com.pig4cloud.pigx.app.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.admin.api.entity.SysRoleMenu;
import com.pig4cloud.pigx.app.api.entity.AppRoleMenu;
import com.pig4cloud.pigx.app.mapper.AppRoleMenuMapper;
import com.pig4cloud.pigx.app.service.AppRoleMenuService;
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 角色菜单表
*
@@ -31,4 +39,20 @@ import org.springframework.stereotype.Service;
@Service
public class AppRoleMenuServiceImpl extends ServiceImpl<AppRoleMenuMapper, AppRoleMenu> implements AppRoleMenuService {
@Override
public Boolean saveRoleMenus(Long roleId, String menuIds) {
this.remove(Wrappers.<AppRoleMenu>query().lambda().eq(AppRoleMenu::getRoleId, roleId));
if (StrUtil.isBlank(menuIds)) {
return Boolean.TRUE;
}
List<AppRoleMenu> roleMenuList = Arrays.stream(menuIds.split(StrUtil.COMMA)).map(menuId -> {
AppRoleMenu roleMenu = new AppRoleMenu();
roleMenu.setRoleId(roleId);
roleMenu.setMenuId(Long.valueOf(menuId));
return roleMenu;
}).collect(Collectors.toList());
this.saveBatch(roleMenuList);
return Boolean.TRUE;
}
}
@@ -18,10 +18,15 @@ package com.pig4cloud.pigx.app.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.app.api.entity.AppRole;
import com.pig4cloud.pigx.app.api.vo.AppRoleVO;
import com.pig4cloud.pigx.app.mapper.AppRoleMapper;
import com.pig4cloud.pigx.app.service.AppRoleMenuService;
import com.pig4cloud.pigx.app.service.AppRoleService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* app角色表
*
@@ -29,6 +34,17 @@ import org.springframework.stereotype.Service;
* @date 2022-12-07 09:52:03
*/
@Service
@AllArgsConstructor
public class AppRoleServiceImpl extends ServiceImpl<AppRoleMapper, AppRole> implements AppRoleService {
private final AppRoleMenuService appRoleMenuService;
@Override
public Boolean updateRoleMenus(AppRoleVO roleVo) {
return appRoleMenuService.saveRoleMenus(roleVo.getRoleId(), roleVo.getMenuIds());
}
@Override
public List<AppRole> findRolesByUserId(Long userId) {
return baseMapper.listRolesByUserId(userId);
}
}
@@ -17,17 +17,24 @@
package com.pig4cloud.pigx.app.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pig4cloud.pigx.admin.api.entity.SysMenu;
import com.pig4cloud.pigx.admin.api.entity.SysRole;
import com.pig4cloud.pigx.admin.api.entity.SysUserRole;
import com.pig4cloud.pigx.app.api.dto.AppUserDTO;
import com.pig4cloud.pigx.app.api.dto.AppUserInfo;
import com.pig4cloud.pigx.app.api.entity.AppMenu;
import com.pig4cloud.pigx.app.api.entity.AppRole;
import com.pig4cloud.pigx.app.api.entity.AppUser;
import com.pig4cloud.pigx.app.api.entity.AppUserRole;
import com.pig4cloud.pigx.app.mapper.AppUserMapper;
import com.pig4cloud.pigx.app.service.AppMenuService;
import com.pig4cloud.pigx.app.service.AppRoleService;
import com.pig4cloud.pigx.app.service.AppUserRoleService;
import com.pig4cloud.pigx.app.service.AppUserService;
import com.pig4cloud.pigx.app.api.vo.AppUserExcelVO;
@@ -40,7 +47,9 @@ import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -57,6 +66,10 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, AppUser> impl
private final AppUserRoleService appUserRoleService;
private final AppRoleService appRoleService;
private final AppMenuService appMenuService;
/**
* 更新用户
* @param userDTO
@@ -136,4 +149,25 @@ public class AppUserServiceImpl extends ServiceImpl<AppUserMapper, AppUser> impl
return Boolean.TRUE;
}
@Override
public AppUserInfo findUserInfo(AppUser user) {
AppUserInfo info = new AppUserInfo();
info.setAppUser(user);
// 设置角色列表 (ID)
List<Long> roleIds = appRoleService.findRolesByUserId(user.getUserId()).stream().map(AppRole::getRoleId)
.collect(Collectors.toList());
info.setRoles(ArrayUtil.toArray(roleIds, Long.class));
// 设置权限列表(menu.permission)
Set<String> permissions = new HashSet<>();
roleIds.forEach(roleId -> {
List<String> permissionList = appMenuService.findMenuByRoleId(roleId).stream()
.filter(menu -> StrUtil.isNotEmpty(menu.getPermission())).map(AppMenu::getPermission)
.collect(Collectors.toList());
permissions.addAll(permissionList);
});
info.setPermissions(ArrayUtil.toArray(permissions, String.class));
return info;
}
}
@@ -39,4 +39,23 @@
<result property="delFlag" column="del_flag"/>
<result property="tenantId" column="tenant_id"/>
</resultMap>
<!--通过角色查询菜单-->
<select id="listMenusByRoleId" resultMap="appMenuMap">
SELECT app_menu.menu_id,
app_menu.name,
app_menu.permission,
app_menu.path,
app_menu.parent_id,
app_menu.sort_order,
app_menu.menu_type,
app_menu.visible,
app_menu.create_time,
app_menu.update_time,
app_menu.del_flag
FROM app_menu
LEFT JOIN app_role_menu ON app_menu.menu_id = app_role_menu.menu_id
WHERE app_menu.del_flag = '0'
AND app_role_menu.role_id = #{roleId}
ORDER BY app_menu.sort_order DESC
</select>
</mapper>
+7
View File
@@ -152,6 +152,13 @@
<artifactId>pigx-upms-api</artifactId>
<version>${pigx.version}</version>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-app-server-api</artifactId>
<version>${pigx.version}</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
@@ -40,4 +40,9 @@ public interface ServiceNameConstants {
*/
String TX_MANAGER = "pigx-tx-manager";
/**
* app服务
*/
String APP_SERVER = "pigx-app-server-biz";
}
@@ -100,4 +100,10 @@ public interface ErrorCodes {
*/
String SYS_CONNECT_CP_USER_SYNC_ERROR = "sys.connect.cp.user.sync.error";
/**
* 用户信息为空
*/
String APP_USER_USERINFO_EMPTY = "app.user.userInfo.empty";
}
@@ -17,3 +17,4 @@ sys.dict.delete.system=\u7CFB\u7EDF\u5185\u7F6E\u5B57\u5178\u9879\u76EE\u4E0D\u8
sys.dict.update.system=\u7CFB\u7EDF\u5185\u7F6E\u5B57\u5178\u9879\u76EE\u4E0D\u80FD\u4FEE\u6539
sys.connect.cp.dept.sync.error=\u83B7\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u90E8\u95E8\u5217\u8868\u5931\u8D25
sys.connect.cp.user.sync.error=\u83B7\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237\u5217\u8868\u5931\u8D25
app.user.userInfo.empty={0} \u7528\u6237\u4FE1\u606F\u4E3A\u7A7A
+5
View File
@@ -68,5 +68,10 @@
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-upms-api</artifactId>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-app-server-api</artifactId>
</dependency>
</dependencies>
</project>
@@ -16,15 +16,32 @@
package com.pig4cloud.pigx.common.security.service;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ArrayUtil;
import com.pig4cloud.pigx.admin.api.dto.UserInfo;
import com.pig4cloud.pigx.admin.api.feign.RemoteUserService;
import com.pig4cloud.pigx.admin.api.entity.SysUser;
import com.pig4cloud.pigx.app.api.dto.AppUserInfo;
import com.pig4cloud.pigx.app.api.entity.AppUser;
import com.pig4cloud.pigx.app.api.feign.RemoteAppUserService;
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.core.util.RetOps;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* 用户详细信息
@@ -35,30 +52,64 @@ import org.springframework.security.core.userdetails.UserDetailsService;
@RequiredArgsConstructor
public class PigxAppUserDetailsServiceImpl implements PigxUserDetailsService {
private final UserDetailsService pigxDefaultUserDetailsServiceImpl;
private final RemoteUserService remoteUserService;
private final CacheManager cacheManager;
private final RemoteAppUserService remoteAppUserService;
/**
* 手机号登录
* @param phone 手机号
* 用户密码登录
* @param username 用户密码登录
* @return
*/
@Override
@SneakyThrows
public UserDetails loadUserByUsername(String phone) {
R<UserInfo> result = remoteUserService.social(phone, SecurityConstants.FROM_IN);
return getUserDetails(result);
public UserDetails loadUserByUsername(String username) {
Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
if (cache != null && cache.get(username) != null) {
return cache.get(username, PigxUser.class);
}
R<AppUserInfo> info = remoteAppUserService.info(username, SecurityConstants.FROM_IN);
return this.getUserDetailsAppUser(info);
}
UserDetails getUserDetailsAppUser(R<AppUserInfo> result) {
// @formatter:off
return RetOps.of(result)
.getData()
.map(this::convertUserDetailsAppUser)
.orElseThrow(() -> new UsernameNotFoundException("用户不存在"));
// @formatter:on
}
/**
* check-token 使用
* @param pigxUser user
* @return UserDetails
* UserInfo 转 UserDetails
* @param info
* @return 返回UserDetails对象
*/
UserDetails convertUserDetailsAppUser(AppUserInfo info) {
Set<String> dbAuthsSet = new HashSet<>();
if (ArrayUtil.isNotEmpty(info.getRoles())) {
// 获取角色
Arrays.stream(info.getRoles()).forEach(roleId -> dbAuthsSet.add(SecurityConstants.ROLE + roleId));
// 获取资源
dbAuthsSet.addAll(Arrays.asList(info.getPermissions()));
}
Collection<? extends GrantedAuthority> authorities = AuthorityUtils
.createAuthorityList(dbAuthsSet.toArray(new String[0]));
AppUser user = info.getAppUser();
// 构造security用户
return new PigxUser(user.getUserId(), user.getUsername(), null, user.getPhone(), user.getAvatar(),
user.getNickname(), user.getName(), user.getEmail(), user.getTenantId(),
SecurityConstants.BCRYPT + user.getPassword(), true, true, true,
!CommonConstants.STATUS_LOCK.equals(user.getLockFlag()), authorities);
}
@Override
public UserDetails loadUserByUser(PigxUser pigxUser) {
return pigxDefaultUserDetailsServiceImpl.loadUserByUsername(pigxUser.getUsername());
public int getOrder() {
return 10;
}
/**
@@ -69,7 +120,7 @@ public class PigxAppUserDetailsServiceImpl implements PigxUserDetailsService {
*/
@Override
public boolean support(String clientId, String grantType) {
return SecurityConstants.GRANT_MOBILE.equals(grantType);
return clientId.equals("app");
}
}