mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: [auth] PowerJobLoginService
This commit is contained in:
parent
cda55c918b
commit
0caa854409
@ -97,6 +97,11 @@
|
||||
<artifactId>powerjob-server-migrate</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-server-auth</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-server-starter</artifactId>
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package tech.powerjob.server.auth;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* PowerJob 的 登陆用户
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/3/20
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class PowerJobUser implements Serializable {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 手机号
|
||||
*/
|
||||
private String phone;
|
||||
/**
|
||||
* 邮箱地址
|
||||
*/
|
||||
private String email;
|
||||
/**
|
||||
* webHook
|
||||
*/
|
||||
private String webHook;
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
private String extra;
|
||||
|
||||
/* ************** 以上为数据库字段 ************** */
|
||||
|
||||
private String jwtToken;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package tech.powerjob.server.auth.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 鉴权错误信息
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/11
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum AuthErrorCode {
|
||||
|
||||
USER_NOT_LOGIN("-100", "UserNotLoggedIn"),
|
||||
|
||||
NO_PERMISSION("-200", "NoPermission"),
|
||||
|
||||
/**
|
||||
* 无效请求,一般是参数问题
|
||||
*/
|
||||
INVALID_REQUEST("-300", "INVALID_REQUEST")
|
||||
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String msg;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package tech.powerjob.server.auth.common;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 鉴权相关错误
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
@Getter
|
||||
public class PowerJobAuthException extends RuntimeException {
|
||||
|
||||
private final String code;
|
||||
|
||||
private final String msg;
|
||||
|
||||
public PowerJobAuthException(AuthErrorCode errorCode) {
|
||||
this.code = errorCode.getCode();
|
||||
this.msg = errorCode.getMsg();
|
||||
}
|
||||
|
||||
public PowerJobAuthException(AuthErrorCode errorCode, String extraMsg) {
|
||||
this.code = errorCode.getCode();
|
||||
this.msg = errorCode.getMsg().concat(":").concat(extraMsg);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package tech.powerjob.server.auth.jwt;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JWT 服务
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/3/20
|
||||
*/
|
||||
public interface JwtService {
|
||||
|
||||
String build(Map<String, Object> body, String extraSk);
|
||||
|
||||
Map<String, Object> parse(String jwt, String extraSk);
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package tech.powerjob.server.auth.jwt;
|
||||
|
||||
/**
|
||||
* JWT 安全性的核心
|
||||
* 对安全性有要求的接入方,可以自行重新该方法,自定义自己的安全 token 生成策略
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/3/20
|
||||
*/
|
||||
public interface SecretProvider {
|
||||
|
||||
String fetchSecretKey();
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package tech.powerjob.server.auth.jwt.impl;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import tech.powerjob.server.auth.jwt.SecretProvider;
|
||||
|
||||
/**
|
||||
* PowerJob 默认实现
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/3/20
|
||||
*/
|
||||
@Component
|
||||
public class DefaultSecretProvider implements SecretProvider {
|
||||
@Override
|
||||
public String fetchSecretKey() {
|
||||
return "ZQQZJ";
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package tech.powerjob.server.auth.jwt.impl;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import tech.powerjob.server.auth.jwt.JwtService;
|
||||
import tech.powerjob.server.auth.jwt.SecretProvider;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.security.Key;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* JWT 默认实现
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/3/20
|
||||
*/
|
||||
@Service
|
||||
public class JwtServiceImpl implements JwtService {
|
||||
|
||||
@Resource
|
||||
private SecretProvider secretProvider;
|
||||
|
||||
/**
|
||||
* JWT 客户端过期时间
|
||||
*/
|
||||
@Value("${oms.auth.security.jwt.expire-seconds:604800}")
|
||||
private int jwtExpireTime;
|
||||
|
||||
/**
|
||||
* <a href="https://music.163.com/#/song?id=167975">GoodSong</a>
|
||||
*/
|
||||
private static final String BASE_SECURITY =
|
||||
"CengMengXiangZhangJianZouTianYa" +
|
||||
"KanYiKanShiJieDeFanHua" +
|
||||
"NianShaoDeXinZongYouXieQingKuang" +
|
||||
"RuJinWoSiHaiWeiJia"
|
||||
;
|
||||
|
||||
@Override
|
||||
public String build(Map<String, Object> body, String extraSk) {
|
||||
|
||||
final String secret = fetchSk(extraSk);
|
||||
return innerBuild(secret, jwtExpireTime, body);
|
||||
}
|
||||
|
||||
static String innerBuild(String secret, int expireSeconds, Map<String, Object> body) {
|
||||
JwtBuilder jwtBuilder = Jwts.builder()
|
||||
.setHeaderParam("typ", "JWT")
|
||||
.addClaims(body)
|
||||
.setSubject("PowerJob")
|
||||
.setExpiration(new Date(System.currentTimeMillis() + 1000L * expireSeconds))
|
||||
.setId(UUID.randomUUID().toString())
|
||||
.signWith(genSecretKey(secret), SignatureAlgorithm.HS256);
|
||||
return jwtBuilder.compact();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> parse(String jwt, String extraSk) {
|
||||
return innerParse(fetchSk(extraSk), jwt);
|
||||
}
|
||||
|
||||
private String fetchSk(String extraSk) {
|
||||
if (StringUtils.isEmpty(extraSk)) {
|
||||
return secretProvider.fetchSecretKey();
|
||||
}
|
||||
return secretProvider.fetchSecretKey().concat(extraSk);
|
||||
}
|
||||
|
||||
static Map<String, Object> innerParse(String secret, String jwtStr) {
|
||||
final Jws<Claims> claimsJws = Jwts.parserBuilder()
|
||||
.setSigningKey(genSecretKey(secret))
|
||||
.build()
|
||||
.parseClaimsJws(jwtStr);
|
||||
Map<String, Object> ret = Maps.newHashMap();
|
||||
ret.putAll(claimsJws.getBody());
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static Key genSecretKey(String secret) {
|
||||
byte[] keyBytes = Decoders.BASE64.decode(BASE_SECURITY.concat(secret));
|
||||
return Keys.hmacShaKeyFor(keyBytes);
|
||||
}
|
||||
|
||||
}
|
@ -1,18 +1,19 @@
|
||||
package tech.powerjob.server.auth.login;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 登录上下文
|
||||
* 第三方登录请求
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
@Data
|
||||
public class LoginContext {
|
||||
@Accessors(chain = true)
|
||||
public class ThirdPartyLoginRequest {
|
||||
|
||||
/**
|
||||
* 原始参数,给第三方登录方式一个服务端和前端交互的数据通道。PowerJob 本身不感知其中的内容
|
||||
@ -20,6 +21,4 @@ public class LoginContext {
|
||||
private String originParams;
|
||||
|
||||
private transient HttpServletRequest httpServletRequest;
|
||||
|
||||
private transient HttpServletResponse httpServletResponse;
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package tech.powerjob.server.auth.login;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 第三方登录服务
|
||||
*
|
||||
@ -19,13 +21,13 @@ public interface ThirdPartyLoginService {
|
||||
* @param loginContext 上下文
|
||||
* @return 重定向地址
|
||||
*/
|
||||
String generateLoginUrl(LoginContext loginContext);
|
||||
String generateLoginUrl(HttpServletRequest httpServletRequest);
|
||||
|
||||
/**
|
||||
* 执行第三方登录
|
||||
* @param loginContext 上下文
|
||||
* @return 登录地址
|
||||
*/
|
||||
ThirdPartyUser login(LoginContext loginContext);
|
||||
ThirdPartyUser login(ThirdPartyLoginRequest loginRequest);
|
||||
|
||||
}
|
||||
|
@ -10,12 +10,10 @@ import lombok.SneakyThrows;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.server.auth.login.LoginContext;
|
||||
import tech.powerjob.server.auth.login.LoginTypeInfo;
|
||||
import tech.powerjob.server.auth.login.ThirdPartyLoginService;
|
||||
import tech.powerjob.server.auth.login.ThirdPartyUser;
|
||||
import tech.powerjob.server.auth.login.*;
|
||||
import tech.powerjob.server.common.Loggers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@ -68,7 +66,7 @@ public class DingTalkLoginService implements ThirdPartyLoginService {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public String generateLoginUrl(LoginContext loginContext) {
|
||||
public String generateLoginUrl(HttpServletRequest httpServletRequest) {
|
||||
if (StringUtils.isAnyEmpty(dingTalkAppKey, dingTalkAppSecret, dingTalkCallbackUrl)) {
|
||||
throw new IllegalArgumentException("please config 'oms.auth.dingtalk.appkey', 'oms.auth.dingtalk.appSecret' and 'oms.auth.dingtalk.callbackUrl' in properties!");
|
||||
}
|
||||
@ -87,7 +85,7 @@ public class DingTalkLoginService implements ThirdPartyLoginService {
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public ThirdPartyUser login(LoginContext loginContext) {
|
||||
public ThirdPartyUser login(ThirdPartyLoginRequest loginRequest) {
|
||||
try {
|
||||
com.aliyun.dingtalkoauth2_1_0.Client client = authClient();
|
||||
GetUserTokenRequest getUserTokenRequest = new GetUserTokenRequest()
|
||||
@ -95,7 +93,7 @@ public class DingTalkLoginService implements ThirdPartyLoginService {
|
||||
.setClientId(dingTalkAppKey)
|
||||
//应用基础信息-应用信息的AppSecret,,请务必替换为开发的应用AppSecret
|
||||
.setClientSecret(dingTalkAppSecret)
|
||||
.setCode(loginContext.getHttpServletRequest().getParameter("authCode"))
|
||||
.setCode(loginRequest.getHttpServletRequest().getParameter("authCode"))
|
||||
.setGrantType("authorization_code");
|
||||
GetUserTokenResponse getUserTokenResponse = client.getUserToken(getUserTokenRequest);
|
||||
//获取用户个人 token
|
||||
|
@ -3,8 +3,8 @@ package tech.powerjob.server.auth.login.impl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.server.auth.login.LoginContext;
|
||||
import tech.powerjob.server.auth.login.LoginTypeInfo;
|
||||
import tech.powerjob.server.auth.login.ThirdPartyLoginRequest;
|
||||
import tech.powerjob.server.auth.login.ThirdPartyLoginService;
|
||||
import tech.powerjob.server.auth.login.ThirdPartyUser;
|
||||
import tech.powerjob.server.common.Loggers;
|
||||
@ -14,6 +14,7 @@ import tech.powerjob.server.persistence.remote.model.UserInfoDO;
|
||||
import tech.powerjob.server.persistence.remote.repository.UserInfoRepository;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -25,7 +26,7 @@ import java.util.Optional;
|
||||
* @since 2023/3/20
|
||||
*/
|
||||
@Service
|
||||
public class PowerJobLoginService implements ThirdPartyLoginService {
|
||||
public class PowerJobThirdPartyLoginService implements ThirdPartyLoginService {
|
||||
|
||||
@Resource
|
||||
private UserInfoRepository userInfoRepository;
|
||||
@ -44,14 +45,14 @@ public class PowerJobLoginService implements ThirdPartyLoginService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateLoginUrl(LoginContext loginContext) {
|
||||
public String generateLoginUrl(HttpServletRequest httpServletRequest) {
|
||||
// 前端实现跳转,服务端返回特殊指令
|
||||
return "FE-REDIRECT:PowerJob";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThirdPartyUser login(LoginContext loginContext) {
|
||||
final String loginInfo = loginContext.getOriginParams();
|
||||
public ThirdPartyUser login(ThirdPartyLoginRequest loginRequest) {
|
||||
final String loginInfo = loginRequest.getOriginParams();
|
||||
if (StringUtils.isEmpty(loginInfo)) {
|
||||
throw new IllegalArgumentException("can't find login Info");
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package tech.powerjob.server.auth.service.login;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* 执行登录的请求
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
@Data
|
||||
public class LoginRequest {
|
||||
|
||||
/**
|
||||
* 登录类型
|
||||
*/
|
||||
private String loginType;
|
||||
|
||||
/**
|
||||
* 原始参数,给第三方登录方式一个服务端和前端交互的数据通道。PowerJob 本身不感知其中的内容
|
||||
*/
|
||||
private String originParams;
|
||||
|
||||
private transient HttpServletRequest httpServletRequest;
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package tech.powerjob.server.auth.service.login;
|
||||
|
||||
import tech.powerjob.server.auth.PowerJobUser;
|
||||
import tech.powerjob.server.auth.common.PowerJobAuthException;
|
||||
import tech.powerjob.server.auth.login.LoginTypeInfo;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* PowerJob 登录服务
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
public interface PowerJobLoginService {
|
||||
|
||||
/**
|
||||
* 获取全部可登录的类型
|
||||
* @return 全部可登录类型
|
||||
*/
|
||||
List<LoginTypeInfo> fetchSupportLoginTypes();
|
||||
|
||||
|
||||
/**
|
||||
* 获取第三方登录链接
|
||||
* @param httpServletRequest http请求
|
||||
* @return 重定向地址
|
||||
*/
|
||||
String fetchThirdPartyLoginUrl(HttpServletRequest httpServletRequest);
|
||||
|
||||
/**
|
||||
* 执行真正的登录请求,底层调用第三方登录服务完成登录
|
||||
* @param loginRequest 登录请求
|
||||
* @return 登录完成的 PowerJobUser
|
||||
* @throws PowerJobAuthException 鉴权失败抛出异常
|
||||
*/
|
||||
PowerJobUser doLogin(LoginRequest loginRequest) throws PowerJobAuthException;
|
||||
|
||||
/**
|
||||
* 从 JWT 信息中解析用户登录信息
|
||||
* @param httpServletRequest httpServletRequest
|
||||
* @return PowerJob 用户
|
||||
*/
|
||||
Optional<PowerJobUser> ifLogin(HttpServletRequest httpServletRequest);
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
package tech.powerjob.server.auth.service.login.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import tech.powerjob.server.auth.PowerJobUser;
|
||||
import tech.powerjob.server.auth.common.AuthErrorCode;
|
||||
import tech.powerjob.server.auth.common.PowerJobAuthException;
|
||||
import tech.powerjob.server.auth.jwt.JwtService;
|
||||
import tech.powerjob.server.auth.login.LoginTypeInfo;
|
||||
import tech.powerjob.server.auth.login.ThirdPartyLoginRequest;
|
||||
import tech.powerjob.server.auth.login.ThirdPartyLoginService;
|
||||
import tech.powerjob.server.auth.login.ThirdPartyUser;
|
||||
import tech.powerjob.server.auth.service.login.LoginRequest;
|
||||
import tech.powerjob.server.auth.service.login.PowerJobLoginService;
|
||||
import tech.powerjob.server.common.Loggers;
|
||||
import tech.powerjob.server.persistence.remote.model.UserInfoDO;
|
||||
import tech.powerjob.server.persistence.remote.repository.UserInfoRepository;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* PowerJob 登录服务
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2024/2/10
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class PowerJobLoginServiceImpl implements PowerJobLoginService {
|
||||
|
||||
|
||||
private final JwtService jwtService;
|
||||
private final UserInfoRepository userInfoRepository;
|
||||
private final Map<String, ThirdPartyLoginService> code2ThirdPartyLoginService;
|
||||
|
||||
private static final String JWT_NAME = "power_jwt";
|
||||
|
||||
private static final String KEY_USERNAME = "userName";
|
||||
|
||||
@Autowired
|
||||
public PowerJobLoginServiceImpl(JwtService jwtService, UserInfoRepository userInfoRepository, List<ThirdPartyLoginService> thirdPartyLoginServices) {
|
||||
|
||||
this.jwtService = jwtService;
|
||||
this.userInfoRepository = userInfoRepository;
|
||||
|
||||
code2ThirdPartyLoginService = Maps.newHashMap();
|
||||
thirdPartyLoginServices.forEach(s -> {
|
||||
code2ThirdPartyLoginService.put(s.loginType().getType(), s);
|
||||
log.info("[PowerJobLoginService] register ThirdPartyLoginService: {}", s.loginType());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<LoginTypeInfo> fetchSupportLoginTypes() {
|
||||
return Lists.newArrayList(code2ThirdPartyLoginService.values()).stream().map(ThirdPartyLoginService::loginType).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fetchThirdPartyLoginUrl(HttpServletRequest httpServletRequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PowerJobUser doLogin(LoginRequest loginRequest) throws PowerJobAuthException {
|
||||
final String loginType = loginRequest.getLoginType();
|
||||
final ThirdPartyLoginService thirdPartyLoginService = fetchBizLoginService(loginType);
|
||||
|
||||
ThirdPartyLoginRequest thirdPartyLoginRequest = new ThirdPartyLoginRequest()
|
||||
.setOriginParams(loginRequest.getOriginParams())
|
||||
.setHttpServletRequest(loginRequest.getHttpServletRequest());
|
||||
|
||||
final ThirdPartyUser bizUser = thirdPartyLoginService.login(thirdPartyLoginRequest);
|
||||
|
||||
String dbUserName = String.format("%s_%s", loginType, bizUser.getUsername());
|
||||
Optional<UserInfoDO> powerJobUserOpt = userInfoRepository.findByUsername(dbUserName);
|
||||
|
||||
// 如果不存在用户,先同步创建用户
|
||||
if (!powerJobUserOpt.isPresent()) {
|
||||
UserInfoDO newUser = new UserInfoDO();
|
||||
newUser.setUsername(dbUserName);
|
||||
Loggers.WEB.info("[PowerJobLoginService] sync user to PowerJobUserSystem: {}", dbUserName);
|
||||
userInfoRepository.saveAndFlush(newUser);
|
||||
|
||||
powerJobUserOpt = userInfoRepository.findByUsername(dbUserName);
|
||||
}
|
||||
|
||||
PowerJobUser ret = new PowerJobUser();
|
||||
|
||||
// 理论上 100% 存在
|
||||
if (powerJobUserOpt.isPresent()) {
|
||||
final UserInfoDO dbUser = powerJobUserOpt.get();
|
||||
BeanUtils.copyProperties(dbUser, ret);
|
||||
ret.setUsername(dbUserName);
|
||||
}
|
||||
|
||||
fillJwt(ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<PowerJobUser> ifLogin(HttpServletRequest httpServletRequest) {
|
||||
final Optional<String> userNameOpt = parseUserName(httpServletRequest);
|
||||
return userNameOpt.flatMap(uname -> userInfoRepository.findByUsername(uname).map(userInfoDO -> {
|
||||
PowerJobUser powerJobUser = new PowerJobUser();
|
||||
BeanUtils.copyProperties(userInfoDO, powerJobUser);
|
||||
return powerJobUser;
|
||||
}));
|
||||
}
|
||||
|
||||
private ThirdPartyLoginService fetchBizLoginService(String loginType) {
|
||||
final ThirdPartyLoginService loginService = code2ThirdPartyLoginService.get(loginType);
|
||||
if (loginService == null) {
|
||||
throw new PowerJobAuthException(AuthErrorCode.INVALID_REQUEST, "can't find ThirdPartyLoginService by type: " + loginType);
|
||||
}
|
||||
return loginService;
|
||||
}
|
||||
|
||||
private void fillJwt(PowerJobUser powerJobUser) {
|
||||
Map<String, Object> jwtMap = Maps.newHashMap();
|
||||
|
||||
// 不能下发 userId,容易被轮询爆破
|
||||
jwtMap.put(KEY_USERNAME, powerJobUser.getUsername());
|
||||
|
||||
powerJobUser.setJwtToken(jwtService.build(jwtMap, null));
|
||||
}
|
||||
|
||||
private Optional<String> parseUserName(HttpServletRequest httpServletRequest) {
|
||||
// header、cookie 都能获取
|
||||
String jwtStr = httpServletRequest.getHeader(JWT_NAME);
|
||||
if (StringUtils.isEmpty(jwtStr)) {
|
||||
for (Cookie cookie : httpServletRequest.getCookies()) {
|
||||
if (cookie.getName().equals(JWT_NAME)) {
|
||||
jwtStr = cookie.getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (StringUtils.isEmpty(jwtStr)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
final Map<String, Object> jwtBodyMap = jwtService.parse(jwtStr, null);
|
||||
final Object userName = jwtBodyMap.get(KEY_USERNAME);
|
||||
|
||||
if (userName == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(String.valueOf(userName));
|
||||
}
|
||||
}
|
@ -8,14 +8,17 @@ import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户信息表
|
||||
* 5.0.0 可能不兼容改动:为了支持第三方登录,需要通过 username 与第三方登录系统做匹配,该列需要声明为唯一索引,确保全局唯一
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2020/4/12
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(indexes = {
|
||||
@Index(name = "uidx01_user_info", columnList = "username"),
|
||||
@Table(uniqueConstraints = {
|
||||
@UniqueConstraint(name = "uidx01_user_name", columnNames = {"username"})
|
||||
},
|
||||
indexes = {
|
||||
@Index(name = "uidx02_user_info", columnList = "email")
|
||||
})
|
||||
public class UserInfoDO {
|
||||
|
@ -43,6 +43,10 @@
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-server-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-server-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-server-migrate</artifactId>
|
||||
|
@ -0,0 +1,26 @@
|
||||
package tech.powerjob.server.web.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import tech.powerjob.server.auth.login.LoginTypeInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 登录 & 权限相关
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/4/16
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/auth")
|
||||
public class AuthController {
|
||||
|
||||
@GetMapping("/listSupportLoginTypes")
|
||||
public ResultDTO<List<LoginTypeInfo>> listSupportLoginTypes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user