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