131 lines
5.3 KiB
Java
131 lines
5.3 KiB
Java
package com.designhub.controller;
|
||
|
||
import com.designhub.common.Result;
|
||
import com.designhub.dto.LoginDTO;
|
||
import com.designhub.dto.RegisterDTO;
|
||
import com.designhub.entity.User;
|
||
import com.designhub.exception.BusinessException;
|
||
import com.designhub.service.UserService;
|
||
import com.designhub.util.JwtUtil;
|
||
import com.designhub.vo.LoginVO;
|
||
import com.designhub.vo.UserInfoVO;
|
||
import io.swagger.v3.oas.annotations.Operation;
|
||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||
import jakarta.validation.Valid;
|
||
import lombok.RequiredArgsConstructor;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.web.bind.annotation.*;
|
||
|
||
import java.util.HashMap;
|
||
import java.util.Map;
|
||
|
||
/**
|
||
* 认证控制器
|
||
*/
|
||
@Slf4j
|
||
@Tag(name = "用户认证", description = "用户登录、登出、刷新令牌等接口")
|
||
@RestController
|
||
@RequestMapping("/api/auth")
|
||
@RequiredArgsConstructor
|
||
public class AuthController {
|
||
|
||
private final UserService userService;
|
||
private final JwtUtil jwtUtil;
|
||
|
||
@Operation(summary = "用户注册", description = "新用户注册")
|
||
@PostMapping("/register")
|
||
public Result<User> register(@Valid @RequestBody RegisterDTO registerDTO) {
|
||
log.info("用户注册请求: {}", registerDTO.getUsername());
|
||
User user = userService.register(registerDTO);
|
||
return Result.success(user);
|
||
}
|
||
|
||
@Operation(summary = "用户登录", description = "支持密码登录、钉钉登录、Casdoor登录")
|
||
@PostMapping("/login")
|
||
public Result<LoginVO> login(@Valid @RequestBody LoginDTO loginDTO) {
|
||
log.info("用户登录请求: {}", loginDTO.getUsername());
|
||
LoginVO loginVO = userService.login(loginDTO);
|
||
return Result.success(loginVO);
|
||
}
|
||
|
||
@Operation(summary = "获取当前用户信息", description = "根据Token获取当前登录用户信息")
|
||
@GetMapping("/userinfo")
|
||
public Result<UserInfoVO> getUserInfo(@RequestHeader(value = "Authorization", required = false) String authHeader) {
|
||
log.info("获取用户信息");
|
||
String token = jwtUtil.extractTokenFromHeader(authHeader);
|
||
UserInfoVO userInfo = userService.getUserInfoByToken(token);
|
||
return Result.success(userInfo);
|
||
}
|
||
|
||
@Operation(summary = "用户登出", description = "退出登录,清除Token")
|
||
@PostMapping("/logout")
|
||
public Result<String> logout(@RequestHeader(value = "Authorization", required = false) String authHeader) {
|
||
log.info("用户登出");
|
||
// Token是无状态的,前端删除即可
|
||
// 如果需要黑名单机制,可以在Redis中记录
|
||
return Result.success("登出成功");
|
||
}
|
||
|
||
@Operation(summary = "刷新令牌", description = "使用刷新令牌获取新的访问令牌")
|
||
@PostMapping("/refresh")
|
||
public Result<LoginVO> refresh(@RequestHeader("Authorization") String authHeader) {
|
||
log.info("刷新令牌");
|
||
LoginVO loginVO = userService.refreshToken(authHeader);
|
||
return Result.success(loginVO);
|
||
}
|
||
|
||
@Operation(summary = "钉钉扫码登录回调", description = "接收钉钉扫码登录的回调 - 使用OAuth 2.0流程")
|
||
@GetMapping("/dingtalk/callback")
|
||
@SuppressWarnings("unchecked")
|
||
public Result<LoginVO> dingtalkCallback(
|
||
@RequestParam String code,
|
||
@RequestParam(required = false) String state) {
|
||
log.info("钉钉登录回调 - code: {}, state: {}",
|
||
code.substring(0, Math.min(10, code.length())) + "...", state);
|
||
|
||
// 使用新的OAuth 2.0流程登录
|
||
LoginDTO loginDTO = new LoginDTO();
|
||
loginDTO.setLoginType("dingtalk");
|
||
loginDTO.setAuthCode(code);
|
||
|
||
try {
|
||
LoginVO loginVO = userService.login(loginDTO);
|
||
log.info("钉钉登录成功: {}", loginVO.getUsername());
|
||
return Result.success(loginVO);
|
||
} catch (BusinessException e) {
|
||
// 检查是否需要选择部门
|
||
if (e.getMessage() != null && e.getMessage().startsWith("NEED_SELECT_DEPT:")) {
|
||
String[] parts = e.getMessage().split(":");
|
||
Map<String, Object> data = new HashMap<>();
|
||
data.put("needSelectDept", true);
|
||
data.put("userId", parts[1]);
|
||
data.put("dingDepartments", parts.length > 2 ? parts[2] : "");
|
||
Result<Map<String, Object>> result = Result.error(1901, "需要选择部门", data);
|
||
return (Result<LoginVO>) (Result<?>) result;
|
||
}
|
||
log.error("钉钉登录失败", e);
|
||
return Result.error(e.getMessage());
|
||
} catch (Exception e) {
|
||
log.error("钉钉登录失败", e);
|
||
return Result.error("钉钉登录失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
@Operation(summary = "钉钉用户选择部门", description = "首次登录时选择系统部门")
|
||
@PostMapping("/dingtalk/select-department")
|
||
public Result<LoginVO> selectDepartment(
|
||
@RequestParam Long userId,
|
||
@RequestParam Long deptId) {
|
||
log.info("钉钉用户选择部门: userId={}, deptId={}", userId, deptId);
|
||
|
||
try {
|
||
LoginVO loginVO = userService.completeDingTalkUserSetup(userId, deptId);
|
||
return Result.success(loginVO);
|
||
} catch (Exception e) {
|
||
log.error("选择部门失败", e);
|
||
return Result.error("选择部门失败: " + e.getMessage());
|
||
}
|
||
}
|
||
}
|
||
|