package com.iailab.module.system.controller.admin.auth;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
import cn.hutool.core.util.StrUtil;
|
import com.iailab.framework.common.enums.CommonStatusEnum;
|
import com.iailab.framework.common.enums.UserTypeEnum;
|
import com.iailab.framework.common.pojo.CommonResult;
|
import com.iailab.framework.common.util.object.BeanUtils;
|
import com.iailab.framework.security.config.SecurityProperties;
|
import com.iailab.framework.security.core.LoginUser;
|
import com.iailab.framework.security.core.util.SecurityFrameworkUtils;
|
import com.iailab.module.system.controller.admin.app.vo.AppMenuRespVO;
|
import com.iailab.module.system.controller.admin.app.vo.AppRespVO;
|
import com.iailab.module.system.controller.admin.auth.vo.*;
|
import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
|
import com.iailab.module.system.controller.admin.permission.vo.menu.MenuRespVO;
|
import com.iailab.module.system.convert.auth.AuthConvert;
|
import com.iailab.module.system.dal.dataobject.app.AppDO;
|
import com.iailab.module.system.dal.dataobject.permission.MenuDO;
|
import com.iailab.module.system.dal.dataobject.permission.RoleDO;
|
import com.iailab.module.system.dal.dataobject.user.AdminUserDO;
|
import com.iailab.module.system.enums.logger.LoginLogTypeEnum;
|
import com.iailab.module.system.enums.permission.MenuTypeEnum;
|
import com.iailab.module.system.service.app.AppService;
|
import com.iailab.module.system.service.auth.AdminAuthService;
|
import com.iailab.module.system.service.permission.MenuService;
|
import com.iailab.module.system.service.permission.PermissionService;
|
import com.iailab.module.system.service.permission.RoleService;
|
import com.iailab.module.system.service.social.SocialClientService;
|
import com.iailab.module.system.service.user.AdminUserService;
|
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameters;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.security.core.Authentication;
|
import org.springframework.validation.annotation.Validated;
|
import org.springframework.web.bind.annotation.*;
|
|
import javax.annotation.Resource;
|
import javax.annotation.security.PermitAll;
|
import javax.servlet.http.HttpServletRequest;
|
import javax.validation.Valid;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import static com.iailab.framework.common.pojo.CommonResult.success;
|
import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet;
|
import static com.iailab.framework.security.core.util.SecurityFrameworkUtils.*;
|
import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId;
|
|
|
@Tag(name = "管理后台 - 认证")
|
@RestController
|
@RequestMapping("/system/auth")
|
@Validated
|
@Slf4j
|
public class AuthController {
|
|
@Resource
|
private AdminAuthService authService;
|
@Resource
|
private AdminUserService userService;
|
@Resource
|
private RoleService roleService;
|
@Resource
|
private MenuService menuService;
|
@Resource
|
private PermissionService permissionService;
|
@Resource
|
private SocialClientService socialClientService;
|
@Resource
|
private SecurityProperties securityProperties;
|
@Resource
|
private AppService appService;
|
|
@PostMapping("/login")
|
@PermitAll
|
@Operation(summary = "使用账号密码登录")
|
public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
|
return success(authService.login(reqVO));
|
}
|
|
@PostMapping("/logout")
|
@PermitAll
|
@Operation(summary = "登出系统")
|
public CommonResult<Boolean> logout(HttpServletRequest request) {
|
String token = SecurityFrameworkUtils.obtainAuthorization(request,
|
securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
|
if (StrUtil.isNotBlank(token)) {
|
authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
|
}
|
return success(true);
|
}
|
|
@PostMapping("/refresh-token")
|
@PermitAll
|
@Operation(summary = "刷新令牌")
|
@Parameter(name = "refreshToken", description = "刷新令牌", required = true)
|
public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
|
return success(authService.refreshToken(refreshToken));
|
}
|
|
@PostMapping("/client-refresh-token")
|
@PermitAll
|
@Operation(summary = "刷新令牌")
|
@Parameter(name = "refreshToken", description = "刷新令牌", required = true)
|
public Map<String, Object> refreshToken(@RequestParam("refreshToken") String refreshToken, @RequestParam("clientId") String clientId) {
|
AuthLoginRespVO authLoginRespVO = authService.refreshToken(refreshToken, clientId);
|
Map<String, Object> map = new HashMap<>();
|
map.put("access_token", authLoginRespVO.getAccessToken());
|
map.put("refresh_token", authLoginRespVO.getRefreshToken());
|
map.put("expires_time", LocalDateTimeUtil.toEpochMilli(authLoginRespVO.getExpiresTime()) / 1000L);
|
return map;
|
}
|
|
@GetMapping("/get-permission-info")
|
@Operation(summary = "获取登录用户的权限信息")
|
public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
|
// 1.1 获得用户信息
|
AdminUserDO user = userService.getUser(getLoginUserId());
|
if (user == null) {
|
return success(null);
|
}
|
|
// 1.2 获得角色列表
|
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
|
if (CollUtil.isEmpty(roleIds)) {
|
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
|
}
|
List<RoleDO> roles = roleService.getRoleList(roleIds);
|
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
|
|
// 1.3 获得菜单列表
|
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
|
List<MenuDO> menuList = menuService.getMenuList(menuIds);
|
menuList = menuService.filterDisableMenus(menuList);
|
menuList = menuService.filterMenus(menuList, "system");
|
|
// 2. 拼接结果返回
|
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
|
}
|
|
@GetMapping("/get-app-permission-info")
|
@Operation(summary = "脚手架获取登录用户的权限信息")
|
public CommonResult<AuthPermissionInfoRespVO> getAppPermissionInfo() {
|
// 1.1 获得用户信息
|
AdminUserDO user = userService.getUser(getLoginUserId());
|
if (user == null) {
|
return success(null);
|
}
|
|
// 1.2 获得角色列表
|
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
|
if (CollUtil.isEmpty(roleIds)) {
|
return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
|
}
|
List<RoleDO> roles = roleService.getRoleList(roleIds);
|
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
|
|
// 1.3 获得菜单列表
|
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
|
List<MenuDO> menuList = menuService.getMenuList(menuIds);
|
menuList = menuService.filterDisableMenus(menuList);
|
menuList = menuService.filterMenus(menuList, "app");
|
|
// 2. 拼接结果返回
|
return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
|
}
|
|
@GetMapping("/get-app-permission")
|
@Operation(summary = "获取登录用户的app权限信息")
|
public CommonResult<List<AppRespVO>> getAppPermission() {
|
List<AppRespVO> appList = new ArrayList<>();
|
// 1.1 获得用户信息
|
AdminUserDO user = userService.getUser(getLoginUserId());
|
if (user == null) {
|
return success(null);
|
}
|
// 1.2 获得角色列表
|
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
|
if (CollUtil.isEmpty(roleIds)) {
|
return success(appList);
|
}
|
List<RoleDO> roles = roleService.getRoleList(roleIds);
|
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
|
|
// 1.3 获得应用菜单列表
|
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
|
List<MenuDO> menuList = menuService.getMenuList(menuIds);
|
//只要一级菜单,一级菜单即是应用
|
menuList = menuList.stream().filter(menu -> menu.getParentId() == 0l).collect(Collectors.toList());
|
menuList = menuService.filterDisableMenus(menuList);
|
List<Long> ids = menuList.stream().map(MenuDO::getAppId).collect(Collectors.toList());
|
List<AppDO> appDOS = appService.selectBatchIds(ids);
|
//排序
|
Collections.sort(appDOS, Comparator.comparing(AppDO::getOrderNum));
|
// 2. 拼接结果返回
|
return success(BeanUtils.toBean(appDOS, AppRespVO.class));
|
}
|
|
@GetMapping("/get-app-menu-permission")
|
@Operation(summary = "获取登录用户的app权限信息")
|
public CommonResult<List<AuthPermissionInfoRespVO.MenuVO>> getAppMenuPermission(@RequestParam("id") Long id) {
|
List<AuthPermissionInfoRespVO.MenuVO> menuVOS = new ArrayList<>();
|
// 1.1 获得用户信息
|
AdminUserDO user = userService.getUser(getLoginUserId());
|
if (user == null) {
|
return success(null);
|
}
|
// 1.2 获得角色列表
|
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
|
if (CollUtil.isEmpty(roleIds)) {
|
return success(menuVOS);
|
}
|
List<RoleDO> roles = roleService.getRoleList(roleIds);
|
roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
|
|
// 1.3 获得应用菜单列表
|
Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
|
List<MenuDO> menuList = menuService.getMenuList(menuIds);
|
menuList = menuService.filterDisableMenus(menuList);
|
MenuDO menuDO = menuService.getMenuByAppId(id);
|
AppDO info = appService.getInfo(id);
|
List<MenuDO> children = new LinkedList<>();
|
// 遍历每一层
|
Collection<Long> parentIds = Collections.singleton(menuDO.getId());
|
for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环
|
// 查询当前层,所有的子应用菜单
|
List<MenuDO> menus = menuService.selectListByParentId(parentIds);
|
// 1. 如果没有子菜单,则结束遍历
|
if (CollUtil.isEmpty(menus)) {
|
break;
|
}
|
// 2. 如果有子应用菜单,继续遍历
|
children.addAll(menus);
|
parentIds = convertSet(menus, MenuDO::getId);
|
}
|
children.retainAll(menuList);
|
List<MenuDO> tempChildren = new LinkedList<>();
|
//为每一个二级菜单(非外链菜单)增加一个隐藏父级目录
|
children.stream().forEach(menu -> {
|
if (menu.getParentId().equals(menuDO.getId())) {
|
if(menu.getType().equals(MenuTypeEnum.MENU.getType())) {
|
MenuDO parentMenu = BeanUtils.toBean(menu, MenuDO.class);
|
parentMenu.setId(System.currentTimeMillis() + (int) (Math.random() * (99999 - 10000 + 1)) + 10000);
|
parentMenu.setType(MenuTypeEnum.DIR.getType());
|
parentMenu.setVisible(true);
|
parentMenu.setAlwaysShow(false);
|
parentMenu.setParentId(menuDO.getId());
|
parentMenu.setPath("/");
|
menu.setParentId(parentMenu.getId());
|
tempChildren.add(parentMenu);
|
} else if(menu.getType().equals(MenuTypeEnum.DIR.getType())) {
|
// 为应用菜单二级目录前增加“/”
|
if(!menu.getPath().contains("http:") && !menu.getPath().contains("https:")) {
|
menu.setPath("/" + menu.getPath());
|
}
|
}
|
}
|
tempChildren.add(menu);
|
});
|
menuVOS = AuthConvert.INSTANCE.buildMenuTree(tempChildren, menuDO.getId(), menuDO.getPath(), info.getType());
|
// 2. 拼接结果返回
|
return success(menuVOS);
|
}
|
|
// ========== 短信登录相关 ==========
|
|
@PostMapping("/sms-login")
|
@PermitAll
|
@Operation(summary = "使用短信验证码登录")
|
public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
|
return success(authService.smsLogin(reqVO));
|
}
|
|
@PostMapping("/send-sms-code")
|
@PermitAll
|
@Operation(summary = "发送手机验证码")
|
public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
|
authService.sendSmsCode(reqVO);
|
return success(true);
|
}
|
|
// ========== 社交登录相关 ==========
|
|
@GetMapping("/social-auth-redirect")
|
@PermitAll
|
@Operation(summary = "社交授权的跳转")
|
@Parameters({
|
@Parameter(name = "type", description = "社交类型", required = true),
|
@Parameter(name = "redirectUri", description = "回调路径")
|
})
|
public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
|
@RequestParam("redirectUri") String redirectUri) {
|
return success(socialClientService.getAuthorizeUrl(
|
type, UserTypeEnum.ADMIN.getValue(), redirectUri));
|
}
|
|
@PostMapping("/social-login")
|
@PermitAll
|
@Operation(summary = "社交快捷登录,使用 code 授权码", description = "适合未登录的用户,但是社交账号已绑定用户")
|
public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
|
return success(authService.socialLogin(reqVO));
|
}
|
|
}
|