潘志宝
2024-11-21 d338b50afd6504a9676f0a26b3ecbcc844483e7c
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.system.controller.admin.auth;
H 2
3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.util.StrUtil;
5 import com.iailab.framework.common.enums.CommonStatusEnum;
6 import com.iailab.framework.common.enums.UserTypeEnum;
7 import com.iailab.framework.common.pojo.CommonResult;
7da8f1 8 import com.iailab.framework.common.util.object.BeanUtils;
e7c126 9 import com.iailab.framework.security.config.SecurityProperties;
ce910c 10 import com.iailab.framework.security.core.LoginUser;
e7c126 11 import com.iailab.framework.security.core.util.SecurityFrameworkUtils;
7da8f1 12 import com.iailab.module.system.controller.admin.app.vo.AppMenuRespVO;
H 13 import com.iailab.module.system.controller.admin.app.vo.AppRespVO;
e7c126 14 import com.iailab.module.system.controller.admin.auth.vo.*;
818a01 15 import com.iailab.module.system.controller.admin.permission.vo.menu.MenuListReqVO;
7da8f1 16 import com.iailab.module.system.controller.admin.permission.vo.menu.MenuRespVO;
e7c126 17 import com.iailab.module.system.convert.auth.AuthConvert;
818a01 18 import com.iailab.module.system.dal.dataobject.app.AppDO;
e7c126 19 import com.iailab.module.system.dal.dataobject.permission.MenuDO;
H 20 import com.iailab.module.system.dal.dataobject.permission.RoleDO;
21 import com.iailab.module.system.dal.dataobject.user.AdminUserDO;
22 import com.iailab.module.system.enums.logger.LoginLogTypeEnum;
7da8f1 23 import com.iailab.module.system.enums.permission.MenuTypeEnum;
818a01 24 import com.iailab.module.system.service.app.AppService;
e7c126 25 import com.iailab.module.system.service.auth.AdminAuthService;
H 26 import com.iailab.module.system.service.permission.MenuService;
27 import com.iailab.module.system.service.permission.PermissionService;
28 import com.iailab.module.system.service.permission.RoleService;
29 import com.iailab.module.system.service.social.SocialClientService;
30 import com.iailab.module.system.service.user.AdminUserService;
31 import io.swagger.v3.oas.annotations.Operation;
32 import io.swagger.v3.oas.annotations.Parameter;
33 import io.swagger.v3.oas.annotations.Parameters;
34 import io.swagger.v3.oas.annotations.tags.Tag;
35 import lombok.extern.slf4j.Slf4j;
ce910c 36 import org.springframework.security.core.Authentication;
e7c126 37 import org.springframework.validation.annotation.Validated;
H 38 import org.springframework.web.bind.annotation.*;
39
40 import javax.annotation.Resource;
41 import javax.annotation.security.PermitAll;
42 import javax.servlet.http.HttpServletRequest;
43 import javax.validation.Valid;
7da8f1 44 import java.util.*;
H 45 import java.util.stream.Collectors;
e7c126 46
H 47 import static com.iailab.framework.common.pojo.CommonResult.success;
48 import static com.iailab.framework.common.util.collection.CollectionUtils.convertSet;
ce910c 49 import static com.iailab.framework.security.core.util.SecurityFrameworkUtils.*;
818a01 50 import static com.iailab.framework.tenant.core.context.TenantContextHolder.getTenantId;
e7c126 51
d9f9ba 52
e7c126 53 @Tag(name = "管理后台 - 认证")
H 54 @RestController
55 @RequestMapping("/system/auth")
56 @Validated
57 @Slf4j
58 public class AuthController {
59
60     @Resource
61     private AdminAuthService authService;
62     @Resource
63     private AdminUserService userService;
64     @Resource
65     private RoleService roleService;
66     @Resource
67     private MenuService menuService;
68     @Resource
69     private PermissionService permissionService;
70     @Resource
71     private SocialClientService socialClientService;
72     @Resource
73     private SecurityProperties securityProperties;
818a01 74     @Resource
H 75     private AppService appService;
e7c126 76
H 77     @PostMapping("/login")
78     @PermitAll
79     @Operation(summary = "使用账号密码登录")
80     public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
81         return success(authService.login(reqVO));
82     }
83
84     @PostMapping("/logout")
85     @PermitAll
86     @Operation(summary = "登出系统")
87     public CommonResult<Boolean> logout(HttpServletRequest request) {
88         String token = SecurityFrameworkUtils.obtainAuthorization(request,
89                 securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
90         if (StrUtil.isNotBlank(token)) {
91             authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
92         }
93         return success(true);
94     }
95
96     @PostMapping("/refresh-token")
97     @PermitAll
98     @Operation(summary = "刷新令牌")
99     @Parameter(name = "refreshToken", description = "刷新令牌", required = true)
100     public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
101         return success(authService.refreshToken(refreshToken));
102     }
103
104     @GetMapping("/get-permission-info")
105     @Operation(summary = "获取登录用户的权限信息")
106     public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
107         // 1.1 获得用户信息
108         AdminUserDO user = userService.getUser(getLoginUserId());
109         if (user == null) {
110             return success(null);
111         }
112
113         // 1.2 获得角色列表
114         Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
115         if (CollUtil.isEmpty(roleIds)) {
116             return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList()));
117         }
118         List<RoleDO> roles = roleService.getRoleList(roleIds);
119         roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
120
121         // 1.3 获得菜单列表
122         Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
123         List<MenuDO> menuList = menuService.getMenuList(menuIds);
d9f9ba 124         menuList = menuService.filterDisableMenus(menuList);
e7c126 125
H 126         // 2. 拼接结果返回
127         return success(AuthConvert.INSTANCE.convert(user, roles, menuList));
128     }
129
7da8f1 130     @GetMapping("/get-app-permission")
818a01 131     @Operation(summary = "获取登录用户的app权限信息")
7da8f1 132     public CommonResult<List<AppRespVO>> getAppPermission() {
H 133         List<AppRespVO> appList = new ArrayList<>();
818a01 134         // 1.1 获得用户信息
H 135         AdminUserDO user = userService.getUser(getLoginUserId());
136         if (user == null) {
137             return success(null);
138         }
139         // 1.2 获得角色列表
140         Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
141         if (CollUtil.isEmpty(roleIds)) {
7da8f1 142             return success(appList);
818a01 143         }
H 144         List<RoleDO> roles = roleService.getRoleList(roleIds);
145         roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
146
147         // 1.3 获得应用菜单列表
148         Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
149         List<MenuDO> menuList = menuService.getMenuList(menuIds);
7da8f1 150         //只要一级菜单,一级菜单即是应用
H 151         menuList = menuList.stream().filter(menu -> menu.getParentId() == 0l).collect(Collectors.toList());
818a01 152         menuList = menuService.filterDisableMenus(menuList);
7da8f1 153         List<Long> ids = menuList.stream().map(MenuDO::getAppId).collect(Collectors.toList());
H 154         List<AppDO> appDOS = appService.selectBatchIds(ids);
155         //排序
156         Collections.sort(appDOS, Comparator.comparing(AppDO::getOrderNum));
818a01 157         // 2. 拼接结果返回
7da8f1 158         return success(BeanUtils.toBean(appDOS, AppRespVO.class));
H 159     }
160
161     @GetMapping("/get-app-menu-permission")
162     @Operation(summary = "获取登录用户的app权限信息")
163     public CommonResult<List<AuthPermissionInfoRespVO.MenuVO>> getAppMenuPermission(@RequestParam("id") Long id) {
164         List<AuthPermissionInfoRespVO.MenuVO> menuVOS = new ArrayList<>();
165         // 1.1 获得用户信息
166         AdminUserDO user = userService.getUser(getLoginUserId());
167         if (user == null) {
168             return success(null);
169         }
170         // 1.2 获得角色列表
171         Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId());
172         if (CollUtil.isEmpty(roleIds)) {
173             return success(menuVOS);
174         }
175         List<RoleDO> roles = roleService.getRoleList(roleIds);
176         roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色
177
178         // 1.3 获得应用菜单列表
179         Set<Long> menuIds = permissionService.getRoleMenuListByRoleId(convertSet(roles, RoleDO::getId));
180         List<MenuDO> menuList = menuService.getMenuList(menuIds);
181         menuList = menuService.filterDisableMenus(menuList);
182         MenuDO menuDO = menuService.getMenuByAppId(id);
ce910c 183         AppDO info = appService.getInfo(id);
7da8f1 184         List<MenuDO> children = new LinkedList<>();
H 185         // 遍历每一层
186         Collection<Long> parentIds = Collections.singleton(menuDO.getId());
187         for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环
188             // 查询当前层,所有的子应用菜单
189             List<MenuDO> menus = menuService.selectListByParentId(parentIds);
190             // 1. 如果没有子菜单,则结束遍历
191             if (CollUtil.isEmpty(menus)) {
192                 break;
193             }
194             // 2. 如果有子应用菜单,继续遍历
195             children.addAll(menus);
196             parentIds = convertSet(menus, MenuDO::getId);
197         }
198         children.retainAll(menuList);
199         List<MenuDO> tempChildren = new LinkedList<>();
200         //为每一个二级菜单增加一个隐藏父级目录
201         children.stream().forEach(menu -> {
202             if (menu.getType().equals(MenuTypeEnum.MENU.getType()) && menu.getParentId().equals(menuDO.getId())) {
203                 MenuDO parentMenu = BeanUtils.toBean(menu, MenuDO.class);
204                 parentMenu.setId(System.currentTimeMillis() + (int) (Math.random() * (99999 - 10000 + 1)) + 10000);
205                 parentMenu.setType(MenuTypeEnum.DIR.getType());
206                 parentMenu.setVisible(true);
207                 parentMenu.setAlwaysShow(false);
208                 parentMenu.setParentId(menuDO.getId());
ce910c 209                 parentMenu.setPath("/");
7da8f1 210                 menu.setParentId(parentMenu.getId());
H 211                 tempChildren.add(parentMenu);
212                 tempChildren.add(menu);
213             } else {
214                 tempChildren.add(menu);
215             }
216         });
ce910c 217         menuVOS = AuthConvert.INSTANCE.buildMenuTree(tempChildren, menuDO.getId(), menuDO.getPath(), info.getType());
7da8f1 218         // 2. 拼接结果返回
H 219         return success(menuVOS);
818a01 220     }
H 221
e7c126 222     // ========== 短信登录相关 ==========
H 223
224     @PostMapping("/sms-login")
225     @PermitAll
226     @Operation(summary = "使用短信验证码登录")
227     public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
228         return success(authService.smsLogin(reqVO));
229     }
230
231     @PostMapping("/send-sms-code")
232     @PermitAll
233     @Operation(summary = "发送手机验证码")
234     public CommonResult<Boolean> sendLoginSmsCode(@RequestBody @Valid AuthSmsSendReqVO reqVO) {
235         authService.sendSmsCode(reqVO);
236         return success(true);
237     }
238
239     // ========== 社交登录相关 ==========
240
241     @GetMapping("/social-auth-redirect")
242     @PermitAll
243     @Operation(summary = "社交授权的跳转")
244     @Parameters({
245             @Parameter(name = "type", description = "社交类型", required = true),
246             @Parameter(name = "redirectUri", description = "回调路径")
247     })
248     public CommonResult<String> socialLogin(@RequestParam("type") Integer type,
249                                             @RequestParam("redirectUri") String redirectUri) {
250         return success(socialClientService.getAuthorizeUrl(
251                 type, UserTypeEnum.ADMIN.getValue(), redirectUri));
252     }
253
254     @PostMapping("/social-login")
255     @PermitAll
256     @Operation(summary = "社交快捷登录,使用 code 授权码", description = "适合未登录的用户,但是社交账号已绑定用户")
257     public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
258         return success(authService.socialLogin(reqVO));
259     }
260
261 }