mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: [auth] add controller and loginUserHolder api
This commit is contained in:
parent
198ad9bf46
commit
d789d68180
@ -0,0 +1,24 @@
|
||||
package tech.powerjob.server.auth;
|
||||
|
||||
/**
|
||||
* LoginUserHolder
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/4/16
|
||||
*/
|
||||
public class LoginUserHolder {
|
||||
|
||||
private static final ThreadLocal<PowerJobUser> TL = new ThreadLocal<>();
|
||||
|
||||
public static PowerJobUser get() {
|
||||
return TL.get();
|
||||
}
|
||||
|
||||
public static void set(PowerJobUser powerJobUser) {
|
||||
TL.set(powerJobUser);
|
||||
}
|
||||
|
||||
public static void clean() {
|
||||
TL.remove();
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import tech.powerjob.common.Loggers;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.server.auth.LoginUserHolder;
|
||||
import tech.powerjob.server.auth.PowerJobUser;
|
||||
import tech.powerjob.server.auth.anno.ApiPermission;
|
||||
import tech.powerjob.server.auth.service.PowerJobAuthService;
|
||||
@ -54,6 +55,10 @@ public class PowerJobAuthInterceptor implements HandlerInterceptor {
|
||||
|
||||
// 登陆用户进行权限校验
|
||||
final PowerJobUser powerJobUser = loginUserOpt.get();
|
||||
|
||||
// 写入上下文
|
||||
LoginUserHolder.set(powerJobUser);
|
||||
|
||||
final boolean hasPermission = powerJobAuthService.hasPermission(request, powerJobUser, apiPermissionAnno);
|
||||
if (hasPermission) {
|
||||
return true;
|
||||
@ -65,6 +70,11 @@ public class PowerJobAuthInterceptor implements HandlerInterceptor {
|
||||
throw new PowerJobException("Permission denied!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler, Exception ex) throws Exception {
|
||||
LoginUserHolder.clean();
|
||||
}
|
||||
|
||||
private static String parseResourceName(ApiPermission apiPermission, HandlerMethod handlerMethod) {
|
||||
final String name = apiPermission.name();
|
||||
if (StringUtils.isNotEmpty(name)) {
|
||||
|
@ -37,10 +37,10 @@ public class JwtServiceImpl implements JwtService {
|
||||
* <a href="https://music.163.com/#/song?id=167975">GoodSong</a>
|
||||
*/
|
||||
private static final String BASE_SECURITY =
|
||||
"CengMengXiangZhangJianZouTianYa" +
|
||||
"KanYiKanShiJieDeFanHua" +
|
||||
"NianShaoDeXinZongYouXieQingKuang" +
|
||||
"RuJinWoSiHaiWeiJia"
|
||||
"死去元知万事空" +
|
||||
"但悲不见九州同" +
|
||||
"王师北定中原日" +
|
||||
"家祭无忘告乃翁"
|
||||
;
|
||||
|
||||
@Override
|
||||
@ -72,7 +72,7 @@ public class JwtServiceImpl implements JwtService {
|
||||
.build()
|
||||
.parseClaimsJws(jwtStr);
|
||||
Map<String, Object> ret = Maps.newHashMap();
|
||||
claimsJws.getBody().forEach(ret::put);
|
||||
ret.putAll(claimsJws.getBody());
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -50,11 +50,11 @@ public class DingTalkBizLoginService implements BizLoginService {
|
||||
@Value("${oms.auth.dingtalk.callbackUrl}")
|
||||
private String dingTalkCallbackUrl;
|
||||
|
||||
private static final String DEFAULT_LOGIN_SERVICE = "DingTalk";
|
||||
private static final String DING_TALK = "DingTalk";
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return DEFAULT_LOGIN_SERVICE;
|
||||
return DING_TALK;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -71,7 +71,7 @@ public class DingTalkBizLoginService implements BizLoginService {
|
||||
"&response_type=code" +
|
||||
"&client_id=" + dingTalkAppKey +
|
||||
"&scope=openid" +
|
||||
"&state=DingTalk" +
|
||||
"&state=" + DING_TALK +
|
||||
"&prompt=consent";
|
||||
Loggers.WEB.info("[DingTalkBizLoginService] login url: {}", url);
|
||||
return url;
|
||||
|
@ -23,7 +23,7 @@ import java.util.Optional;
|
||||
* @since 2023/3/20
|
||||
*/
|
||||
@Service
|
||||
public class DefaultBizLoginService implements BizLoginService {
|
||||
public class PowerJobSelfLoginService implements BizLoginService {
|
||||
|
||||
@Resource
|
||||
private UserInfoRepository userInfoRepository;
|
||||
@ -40,7 +40,7 @@ public class DefaultBizLoginService implements BizLoginService {
|
||||
|
||||
@Override
|
||||
public String loginUrl() {
|
||||
return "forward:/user/loginCallback";
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
@ -5,6 +5,7 @@ import tech.powerjob.server.auth.PowerJobUser;
|
||||
import tech.powerjob.server.auth.anno.ApiPermission;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@ -15,6 +16,8 @@ import java.util.Optional;
|
||||
*/
|
||||
public interface PowerJobAuthService {
|
||||
|
||||
List<String> supportTypes();
|
||||
|
||||
/**
|
||||
* 开始登陆
|
||||
* @param loginContext 请求
|
||||
|
@ -1,6 +1,7 @@
|
||||
package tech.powerjob.server.auth.service;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Multimap;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -39,7 +40,7 @@ public class PowerJobAuthServiceImpl implements PowerJobAuthService {
|
||||
private final UserRoleRepository userRoleRepository;
|
||||
private final Map<String, BizLoginService> type2LoginService = Maps.newHashMap();
|
||||
|
||||
private static final String JWT_NAME = "powerjob_token";
|
||||
private static final String JWT_NAME = "power_jwt";
|
||||
|
||||
private static final String KEY_USERID = "userId";
|
||||
|
||||
@ -52,6 +53,11 @@ public class PowerJobAuthServiceImpl implements PowerJobAuthService {
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<String> supportTypes() {
|
||||
return Lists.newArrayList(type2LoginService.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String startLogin(LoginContext loginContext) {
|
||||
final BizLoginService loginService = fetchBizLoginService(loginContext);
|
||||
@ -68,20 +74,20 @@ public class PowerJobAuthServiceImpl implements PowerJobAuthService {
|
||||
final Optional<UserInfoDO> powerJobUserOpt = userInfoRepository.findByUsername(dbUserName);
|
||||
|
||||
PowerJobUser ret = new PowerJobUser();
|
||||
// 存在则响应 PowerJob 用户
|
||||
// 存在则响应 PowerJob 用户,否则同步在 PowerJob 用户库创建该用户
|
||||
if (powerJobUserOpt.isPresent()) {
|
||||
final UserInfoDO dbUser = powerJobUserOpt.get();
|
||||
BeanUtils.copyProperties(dbUser, ret);
|
||||
ret.setUsername(dbUserName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 同步在 PowerJob 用户库创建该用户
|
||||
} else {
|
||||
UserInfoDO newUser = new UserInfoDO();
|
||||
newUser.setUsername(dbUserName);
|
||||
Loggers.WEB.info("[PowerJobLoginService] sync user to PowerJobUserSystem: {}", dbUserName);
|
||||
userInfoRepository.saveAndFlush(newUser);
|
||||
ret.setUsername(dbUserName);
|
||||
}
|
||||
|
||||
fillJwt(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -164,4 +170,12 @@ public class PowerJobAuthServiceImpl implements PowerJobAuthService {
|
||||
}
|
||||
return loginService;
|
||||
}
|
||||
|
||||
private void fillJwt(PowerJobUser powerJobUser) {
|
||||
Map<String, Object> jwtMap = Maps.newHashMap();
|
||||
|
||||
jwtMap.put(KEY_USERID, powerJobUser.getId());
|
||||
|
||||
powerJobUser.setJwtToken(jwtService.build(jwtMap));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
package tech.powerjob.server.web.controller;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import tech.powerjob.server.auth.LoginContext;
|
||||
import tech.powerjob.server.auth.PowerJobUser;
|
||||
import tech.powerjob.server.auth.service.PowerJobAuthService;
|
||||
import tech.powerjob.server.web.request.UserLoginRequest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 登录 & 权限相关
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/4/16
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
@Resource
|
||||
private PowerJobAuthService powerJobAuthService;
|
||||
|
||||
@GetMapping("/supportTypes")
|
||||
public ResultDTO<List<String>> options() {
|
||||
return ResultDTO.success(powerJobAuthService.supportTypes());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@GetMapping("/startLogin")
|
||||
public String tryLogin(UserLoginRequest loginRequest, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
LoginContext loginContext = new LoginContext()
|
||||
.setLoginType(loginRequest.getType())
|
||||
.setLoginInfo(loginRequest.getLoginInfo())
|
||||
.setHttpServletRequest(request);
|
||||
|
||||
final String realLoginUrl = powerJobAuthService.startLogin(loginContext);
|
||||
// 统一重定向
|
||||
response.sendRedirect(realLoginUrl);
|
||||
return null;
|
||||
}
|
||||
|
||||
@PostMapping("/selfLogin")
|
||||
public ResultDTO<PowerJobUser> selfLogin(LoginContext loginContext, HttpServletResponse httpServletResponse) {
|
||||
try {
|
||||
final PowerJobUser powerJobUser = powerJobAuthService.tryLogin(loginContext);
|
||||
if (powerJobUser == null) {
|
||||
return ResultDTO.failed("USER_NOT_FOUND");
|
||||
}
|
||||
httpServletResponse.addCookie(new Cookie("power_jwt", powerJobUser.getJwtToken()));
|
||||
return ResultDTO.success(powerJobUser);
|
||||
} catch (Exception e) {
|
||||
return ResultDTO.failed(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方账号体系回调登录接口
|
||||
* @param httpServletRequest 请求
|
||||
* @param httpServletResponse 响应
|
||||
* @return 登录结果
|
||||
*/
|
||||
@RequestMapping(value = "/loginCallback", method = {RequestMethod.GET, RequestMethod.POST})
|
||||
public ResultDTO<PowerJobUser> loginCallback(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
|
||||
LoginContext loginContext = new LoginContext()
|
||||
.setHttpServletRequest(httpServletRequest);
|
||||
|
||||
// 常见登录组件的标准规范(钉钉、企业微信、飞书),第三方原样透传
|
||||
final String state = httpServletRequest.getParameter("state");
|
||||
loginContext.setLoginType(state);
|
||||
|
||||
final PowerJobUser powerJobUser = powerJobAuthService.tryLogin(loginContext);
|
||||
|
||||
httpServletResponse.addCookie(new Cookie("power_jwt", powerJobUser.getJwtToken()));
|
||||
return ResultDTO.success(powerJobUser);
|
||||
}
|
||||
}
|
@ -4,25 +4,17 @@ import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import tech.powerjob.server.auth.LoginContext;
|
||||
import tech.powerjob.server.auth.PowerJobUser;
|
||||
import tech.powerjob.server.auth.service.PowerJobAuthService;
|
||||
import tech.powerjob.server.core.service.UserService;
|
||||
import tech.powerjob.server.persistence.remote.model.UserInfoDO;
|
||||
import tech.powerjob.server.persistence.remote.repository.UserInfoRepository;
|
||||
import tech.powerjob.server.web.request.ModifyUserInfoRequest;
|
||||
import tech.powerjob.server.web.request.UserLoginRequest;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -39,46 +31,6 @@ public class UserInfoController {
|
||||
private UserService userService;
|
||||
@Resource
|
||||
private UserInfoRepository userInfoRepository;
|
||||
@Resource
|
||||
private PowerJobAuthService powerJobAuthService;
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@GetMapping("/startLogin")
|
||||
public String tryLogin(UserLoginRequest loginRequest, HttpServletRequest request, HttpServletResponse response) {
|
||||
|
||||
LoginContext loginContext = new LoginContext()
|
||||
.setLoginType(loginRequest.getType())
|
||||
.setLoginInfo(loginRequest.getLoginInfo())
|
||||
.setHttpServletRequest(request);
|
||||
|
||||
final String realLoginUrl = powerJobAuthService.startLogin(loginContext);
|
||||
// 统一重定向
|
||||
response.sendRedirect(realLoginUrl);
|
||||
return null;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/loginCallback", method = {RequestMethod.GET, RequestMethod.POST})
|
||||
public ResultDTO<PowerJobUser> loginCallback(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
|
||||
LoginContext loginContext = new LoginContext()
|
||||
.setHttpServletRequest(httpServletRequest);
|
||||
|
||||
// 尝试读取 body
|
||||
if (RequestMethod.POST.name().equalsIgnoreCase(httpServletRequest.getMethod())) {
|
||||
// TODO: 从 post 读取 body
|
||||
}
|
||||
|
||||
// 钉钉回调
|
||||
final String state = httpServletRequest.getParameter("state");
|
||||
if ("DingTalk".equalsIgnoreCase(state)) {
|
||||
loginContext.setLoginType("DingTalk");
|
||||
}
|
||||
|
||||
final PowerJobUser powerJobUser = powerJobAuthService.tryLogin(loginContext);
|
||||
|
||||
httpServletResponse.addCookie(new Cookie("powerjob_token", powerJobUser.getJwtToken()));
|
||||
return ResultDTO.success(powerJobUser);
|
||||
}
|
||||
|
||||
@PostMapping("save")
|
||||
public ResultDTO<Void> save(@RequestBody ModifyUserInfoRequest request) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user