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 org.springframework.web.servlet.HandlerInterceptor;
|
||||||
import tech.powerjob.common.Loggers;
|
import tech.powerjob.common.Loggers;
|
||||||
import tech.powerjob.common.exception.PowerJobException;
|
import tech.powerjob.common.exception.PowerJobException;
|
||||||
|
import tech.powerjob.server.auth.LoginUserHolder;
|
||||||
import tech.powerjob.server.auth.PowerJobUser;
|
import tech.powerjob.server.auth.PowerJobUser;
|
||||||
import tech.powerjob.server.auth.anno.ApiPermission;
|
import tech.powerjob.server.auth.anno.ApiPermission;
|
||||||
import tech.powerjob.server.auth.service.PowerJobAuthService;
|
import tech.powerjob.server.auth.service.PowerJobAuthService;
|
||||||
@ -54,6 +55,10 @@ public class PowerJobAuthInterceptor implements HandlerInterceptor {
|
|||||||
|
|
||||||
// 登陆用户进行权限校验
|
// 登陆用户进行权限校验
|
||||||
final PowerJobUser powerJobUser = loginUserOpt.get();
|
final PowerJobUser powerJobUser = loginUserOpt.get();
|
||||||
|
|
||||||
|
// 写入上下文
|
||||||
|
LoginUserHolder.set(powerJobUser);
|
||||||
|
|
||||||
final boolean hasPermission = powerJobAuthService.hasPermission(request, powerJobUser, apiPermissionAnno);
|
final boolean hasPermission = powerJobAuthService.hasPermission(request, powerJobUser, apiPermissionAnno);
|
||||||
if (hasPermission) {
|
if (hasPermission) {
|
||||||
return true;
|
return true;
|
||||||
@ -65,6 +70,11 @@ public class PowerJobAuthInterceptor implements HandlerInterceptor {
|
|||||||
throw new PowerJobException("Permission denied!");
|
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) {
|
private static String parseResourceName(ApiPermission apiPermission, HandlerMethod handlerMethod) {
|
||||||
final String name = apiPermission.name();
|
final String name = apiPermission.name();
|
||||||
if (StringUtils.isNotEmpty(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>
|
* <a href="https://music.163.com/#/song?id=167975">GoodSong</a>
|
||||||
*/
|
*/
|
||||||
private static final String BASE_SECURITY =
|
private static final String BASE_SECURITY =
|
||||||
"CengMengXiangZhangJianZouTianYa" +
|
"死去元知万事空" +
|
||||||
"KanYiKanShiJieDeFanHua" +
|
"但悲不见九州同" +
|
||||||
"NianShaoDeXinZongYouXieQingKuang" +
|
"王师北定中原日" +
|
||||||
"RuJinWoSiHaiWeiJia"
|
"家祭无忘告乃翁"
|
||||||
;
|
;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -72,7 +72,7 @@ public class JwtServiceImpl implements JwtService {
|
|||||||
.build()
|
.build()
|
||||||
.parseClaimsJws(jwtStr);
|
.parseClaimsJws(jwtStr);
|
||||||
Map<String, Object> ret = Maps.newHashMap();
|
Map<String, Object> ret = Maps.newHashMap();
|
||||||
claimsJws.getBody().forEach(ret::put);
|
ret.putAll(claimsJws.getBody());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,11 +50,11 @@ public class DingTalkBizLoginService implements BizLoginService {
|
|||||||
@Value("${oms.auth.dingtalk.callbackUrl}")
|
@Value("${oms.auth.dingtalk.callbackUrl}")
|
||||||
private String dingTalkCallbackUrl;
|
private String dingTalkCallbackUrl;
|
||||||
|
|
||||||
private static final String DEFAULT_LOGIN_SERVICE = "DingTalk";
|
private static final String DING_TALK = "DingTalk";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String type() {
|
public String type() {
|
||||||
return DEFAULT_LOGIN_SERVICE;
|
return DING_TALK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -71,7 +71,7 @@ public class DingTalkBizLoginService implements BizLoginService {
|
|||||||
"&response_type=code" +
|
"&response_type=code" +
|
||||||
"&client_id=" + dingTalkAppKey +
|
"&client_id=" + dingTalkAppKey +
|
||||||
"&scope=openid" +
|
"&scope=openid" +
|
||||||
"&state=DingTalk" +
|
"&state=" + DING_TALK +
|
||||||
"&prompt=consent";
|
"&prompt=consent";
|
||||||
Loggers.WEB.info("[DingTalkBizLoginService] login url: {}", url);
|
Loggers.WEB.info("[DingTalkBizLoginService] login url: {}", url);
|
||||||
return url;
|
return url;
|
||||||
|
@ -23,7 +23,7 @@ import java.util.Optional;
|
|||||||
* @since 2023/3/20
|
* @since 2023/3/20
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class DefaultBizLoginService implements BizLoginService {
|
public class PowerJobSelfLoginService implements BizLoginService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserInfoRepository userInfoRepository;
|
private UserInfoRepository userInfoRepository;
|
||||||
@ -40,7 +40,7 @@ public class DefaultBizLoginService implements BizLoginService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String loginUrl() {
|
public String loginUrl() {
|
||||||
return "forward:/user/loginCallback";
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -5,6 +5,7 @@ import tech.powerjob.server.auth.PowerJobUser;
|
|||||||
import tech.powerjob.server.auth.anno.ApiPermission;
|
import tech.powerjob.server.auth.anno.ApiPermission;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,6 +16,8 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
public interface PowerJobAuthService {
|
public interface PowerJobAuthService {
|
||||||
|
|
||||||
|
List<String> supportTypes();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开始登陆
|
* 开始登陆
|
||||||
* @param loginContext 请求
|
* @param loginContext 请求
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package tech.powerjob.server.auth.service;
|
package tech.powerjob.server.auth.service;
|
||||||
|
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -39,7 +40,7 @@ public class PowerJobAuthServiceImpl implements PowerJobAuthService {
|
|||||||
private final UserRoleRepository userRoleRepository;
|
private final UserRoleRepository userRoleRepository;
|
||||||
private final Map<String, BizLoginService> type2LoginService = Maps.newHashMap();
|
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";
|
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
|
@Override
|
||||||
public String startLogin(LoginContext loginContext) {
|
public String startLogin(LoginContext loginContext) {
|
||||||
final BizLoginService loginService = fetchBizLoginService(loginContext);
|
final BizLoginService loginService = fetchBizLoginService(loginContext);
|
||||||
@ -68,20 +74,20 @@ public class PowerJobAuthServiceImpl implements PowerJobAuthService {
|
|||||||
final Optional<UserInfoDO> powerJobUserOpt = userInfoRepository.findByUsername(dbUserName);
|
final Optional<UserInfoDO> powerJobUserOpt = userInfoRepository.findByUsername(dbUserName);
|
||||||
|
|
||||||
PowerJobUser ret = new PowerJobUser();
|
PowerJobUser ret = new PowerJobUser();
|
||||||
// 存在则响应 PowerJob 用户
|
// 存在则响应 PowerJob 用户,否则同步在 PowerJob 用户库创建该用户
|
||||||
if (powerJobUserOpt.isPresent()) {
|
if (powerJobUserOpt.isPresent()) {
|
||||||
final UserInfoDO dbUser = powerJobUserOpt.get();
|
final UserInfoDO dbUser = powerJobUserOpt.get();
|
||||||
BeanUtils.copyProperties(dbUser, ret);
|
BeanUtils.copyProperties(dbUser, ret);
|
||||||
ret.setUsername(dbUserName);
|
ret.setUsername(dbUserName);
|
||||||
return ret;
|
} else {
|
||||||
|
UserInfoDO newUser = new UserInfoDO();
|
||||||
|
newUser.setUsername(dbUserName);
|
||||||
|
Loggers.WEB.info("[PowerJobLoginService] sync user to PowerJobUserSystem: {}", dbUserName);
|
||||||
|
userInfoRepository.saveAndFlush(newUser);
|
||||||
|
ret.setUsername(dbUserName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 同步在 PowerJob 用户库创建该用户
|
fillJwt(ret);
|
||||||
UserInfoDO newUser = new UserInfoDO();
|
|
||||||
newUser.setUsername(dbUserName);
|
|
||||||
Loggers.WEB.info("[PowerJobLoginService] sync user to PowerJobUserSystem: {}", dbUserName);
|
|
||||||
userInfoRepository.saveAndFlush(newUser);
|
|
||||||
ret.setUsername(dbUserName);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -164,4 +170,12 @@ public class PowerJobAuthServiceImpl implements PowerJobAuthService {
|
|||||||
}
|
}
|
||||||
return loginService;
|
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.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import tech.powerjob.common.response.ResultDTO;
|
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.core.service.UserService;
|
||||||
import tech.powerjob.server.persistence.remote.model.UserInfoDO;
|
import tech.powerjob.server.persistence.remote.model.UserInfoDO;
|
||||||
import tech.powerjob.server.persistence.remote.repository.UserInfoRepository;
|
import tech.powerjob.server.persistence.remote.repository.UserInfoRepository;
|
||||||
import tech.powerjob.server.web.request.ModifyUserInfoRequest;
|
import tech.powerjob.server.web.request.ModifyUserInfoRequest;
|
||||||
import tech.powerjob.server.web.request.UserLoginRequest;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
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.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -39,46 +31,6 @@ public class UserInfoController {
|
|||||||
private UserService userService;
|
private UserService userService;
|
||||||
@Resource
|
@Resource
|
||||||
private UserInfoRepository userInfoRepository;
|
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")
|
@PostMapping("save")
|
||||||
public ResultDTO<Void> save(@RequestBody ModifyUserInfoRequest request) {
|
public ResultDTO<Void> save(@RequestBody ModifyUserInfoRequest request) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user