mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: [auth] add login api
This commit is contained in:
parent
0508b902df
commit
198ad9bf46
@ -98,6 +98,11 @@
|
||||
<artifactId>powerjob-server-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.powerjob</groupId>
|
||||
<artifactId>powerjob-server-auth</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>powerjob-server-auth</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
|
@ -16,8 +16,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
public class LoginContext {
|
||||
|
||||
private HttpServletRequest httpServletRequest;
|
||||
/**
|
||||
* 登陆类型
|
||||
*/
|
||||
@ -26,4 +24,6 @@ public class LoginContext {
|
||||
* 登陆信息,取决于登陆类型,比如 PowerJob 自带的账号密码为 uid:xxx;pwd:yyy
|
||||
*/
|
||||
private String loginInfo;
|
||||
|
||||
private transient HttpServletRequest httpServletRequest;
|
||||
}
|
||||
|
@ -39,4 +39,6 @@ public class PowerJobUser implements Serializable {
|
||||
private String extra;
|
||||
|
||||
/* ************** 以上为数据库字段 ************** */
|
||||
|
||||
private String jwtToken;
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import com.google.common.collect.Maps;
|
||||
import io.jsonwebtoken.*;
|
||||
import io.jsonwebtoken.io.Decoders;
|
||||
import io.jsonwebtoken.security.Keys;
|
||||
import io.swagger.v3.oas.annotations.servers.Server;
|
||||
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;
|
||||
|
||||
@ -21,7 +21,7 @@ import java.util.UUID;
|
||||
* @author tjq
|
||||
* @since 2023/3/20
|
||||
*/
|
||||
@Server
|
||||
@Service
|
||||
public class JwtServiceImpl implements JwtService {
|
||||
|
||||
@Resource
|
||||
|
@ -2,8 +2,6 @@ package tech.powerjob.server.auth.login;
|
||||
|
||||
import tech.powerjob.server.auth.LoginContext;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 用户登陆服务
|
||||
*
|
||||
@ -29,5 +27,5 @@ public interface BizLoginService {
|
||||
* @param loginContext 登陆上下文
|
||||
* @return PowerJob 用户
|
||||
*/
|
||||
Optional<BizUser> login(LoginContext loginContext);
|
||||
BizUser login(LoginContext loginContext);
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package tech.powerjob.server.auth.login.impl;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import tech.powerjob.common.Loggers;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.common.utils.DigestUtils;
|
||||
import tech.powerjob.server.auth.LoginContext;
|
||||
import tech.powerjob.server.auth.login.BizLoginService;
|
||||
@ -39,16 +40,15 @@ public class DefaultBizLoginService implements BizLoginService {
|
||||
|
||||
@Override
|
||||
public String loginUrl() {
|
||||
// 默认登陆方式不需要重定向
|
||||
return null;
|
||||
return "forward:/user/loginCallback";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<BizUser> login(LoginContext loginContext) {
|
||||
public BizUser login(LoginContext loginContext) {
|
||||
|
||||
final String loginInfo = loginContext.getLoginInfo();
|
||||
if (StringUtils.isEmpty(loginInfo)) {
|
||||
return Optional.empty();
|
||||
throw new IllegalArgumentException("can't find login Info");
|
||||
}
|
||||
|
||||
final Map<String, String> loginInfoMap = SJ.splitKvString(loginInfo);
|
||||
@ -57,13 +57,13 @@ public class DefaultBizLoginService implements BizLoginService {
|
||||
|
||||
if (StringUtils.isAnyEmpty(username, password)) {
|
||||
Loggers.WEB.debug("[DefaultBizLoginService] username or password is empty, login failed!");
|
||||
return Optional.empty();
|
||||
throw new IllegalArgumentException("username or password is empty!");
|
||||
}
|
||||
|
||||
final Optional<UserInfoDO> userInfoOpt = userInfoRepository.findByUsername(username);
|
||||
if (!userInfoOpt.isPresent()) {
|
||||
Loggers.WEB.debug("[DefaultBizLoginService] can't find user by username: {}", username);
|
||||
return Optional.empty();
|
||||
throw new PowerJobException("can't find user by username: " + username);
|
||||
}
|
||||
|
||||
final UserInfoDO dbUser = userInfoOpt.get();
|
||||
@ -71,11 +71,11 @@ public class DefaultBizLoginService implements BizLoginService {
|
||||
if (s(username, password).equals(dbUser.getPassword())) {
|
||||
BizUser bizUser = new BizUser();
|
||||
bizUser.setUsername(username);
|
||||
return Optional.of(bizUser);
|
||||
return bizUser;
|
||||
}
|
||||
|
||||
Loggers.WEB.debug("[DefaultBizLoginService] user[{}]'s password is not correct, login failed!", username);
|
||||
return Optional.empty();
|
||||
Loggers.WEB.debug("[DefaultBizLoginService] user[{}]'s password is incorrect, login failed!", username);
|
||||
throw new PowerJobException("password is incorrect");
|
||||
}
|
||||
|
||||
private static String s(String username, String password) {
|
||||
|
@ -11,13 +11,13 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import tech.powerjob.common.Loggers;
|
||||
import tech.powerjob.common.exception.PowerJobException;
|
||||
import tech.powerjob.server.auth.LoginContext;
|
||||
import tech.powerjob.server.auth.login.BizLoginService;
|
||||
import tech.powerjob.server.auth.login.BizUser;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* <a href="https://open.dingtalk.com/document/orgapp/tutorial-obtaining-user-personal-information">钉钉账号体系登录第三方网站</a>
|
||||
@ -78,7 +78,8 @@ public class DingTalkBizLoginService implements BizLoginService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<BizUser> login(LoginContext loginContext) {
|
||||
@SneakyThrows
|
||||
public BizUser login(LoginContext loginContext) {
|
||||
try {
|
||||
com.aliyun.dingtalkoauth2_1_0.Client client = authClient();
|
||||
GetUserTokenRequest getUserTokenRequest = new GetUserTokenRequest()
|
||||
@ -100,12 +101,13 @@ public class DingTalkBizLoginService implements BizLoginService {
|
||||
bizUser.setNick(dingUser.getNick());
|
||||
bizUser.setPhone(dingUser.getMobile());
|
||||
bizUser.setEmail(dingUser.getEmail());
|
||||
return Optional.of(bizUser);
|
||||
return bizUser;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Loggers.WEB.error("[DingTalkBizLoginService] login by dingTalk failed!", e);
|
||||
throw e;
|
||||
}
|
||||
return Optional.empty();
|
||||
throw new PowerJobException("login from dingTalk failed!");
|
||||
}
|
||||
|
||||
/* 以下代码均拷自钉钉官网示例 */
|
||||
|
@ -15,12 +15,19 @@ import java.util.Optional;
|
||||
*/
|
||||
public interface PowerJobAuthService {
|
||||
|
||||
/**
|
||||
* 开始登陆
|
||||
* @param loginContext 请求
|
||||
* @return 转发 or 重定向到真正的登陆页
|
||||
*/
|
||||
String startLogin(LoginContext loginContext);
|
||||
|
||||
/**
|
||||
* 执行真正的登陆操作
|
||||
* @param loginContext 登录上下文
|
||||
* @return PowerJob 用户
|
||||
*/
|
||||
Optional<PowerJobUser> login(LoginContext loginContext);
|
||||
PowerJobUser tryLogin(LoginContext loginContext);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -32,7 +32,7 @@ import java.util.*;
|
||||
* @since 2023/3/21
|
||||
*/
|
||||
@Service
|
||||
public class PowerJobLoginServiceImpl implements PowerJobAuthService {
|
||||
public class PowerJobAuthServiceImpl implements PowerJobAuthService {
|
||||
|
||||
private final JwtService jwtService;
|
||||
private final UserInfoRepository userInfoRepository;
|
||||
@ -44,7 +44,7 @@ public class PowerJobLoginServiceImpl implements PowerJobAuthService {
|
||||
private static final String KEY_USERID = "userId";
|
||||
|
||||
@Autowired
|
||||
public PowerJobLoginServiceImpl(List<BizLoginService> loginServices, JwtService jwtService, UserInfoRepository userInfoRepository, UserRoleRepository userRoleRepository) {
|
||||
public PowerJobAuthServiceImpl(List<BizLoginService> loginServices, JwtService jwtService, UserInfoRepository userInfoRepository, UserRoleRepository userRoleRepository) {
|
||||
this.jwtService = jwtService;
|
||||
this.userInfoRepository = userInfoRepository;
|
||||
this.userRoleRepository = userRoleRepository;
|
||||
@ -53,17 +53,16 @@ public class PowerJobLoginServiceImpl implements PowerJobAuthService {
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<PowerJobUser> login(LoginContext loginContext) {
|
||||
public String startLogin(LoginContext loginContext) {
|
||||
final BizLoginService loginService = fetchBizLoginService(loginContext);
|
||||
return loginService.loginUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PowerJobUser tryLogin(LoginContext loginContext) {
|
||||
final String loginType = loginContext.getLoginType();
|
||||
final BizLoginService loginService = type2LoginService.get(loginType);
|
||||
if (loginService == null) {
|
||||
throw new IllegalArgumentException("can't find LoginService by type: " + loginType);
|
||||
}
|
||||
final Optional<BizUser> bizUserOpt = loginService.login(loginContext);
|
||||
if (!bizUserOpt.isPresent()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
final BizUser bizUser = bizUserOpt.get();
|
||||
final BizLoginService loginService = fetchBizLoginService(loginContext);
|
||||
final BizUser bizUser = loginService.login(loginContext);
|
||||
|
||||
String dbUserName = String.format("%s_%s", loginType, bizUser.getUsername());
|
||||
final Optional<UserInfoDO> powerJobUserOpt = userInfoRepository.findByUsername(dbUserName);
|
||||
@ -74,7 +73,7 @@ public class PowerJobLoginServiceImpl implements PowerJobAuthService {
|
||||
final UserInfoDO dbUser = powerJobUserOpt.get();
|
||||
BeanUtils.copyProperties(dbUser, ret);
|
||||
ret.setUsername(dbUserName);
|
||||
return Optional.of(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 同步在 PowerJob 用户库创建该用户
|
||||
@ -84,7 +83,7 @@ public class PowerJobLoginServiceImpl implements PowerJobAuthService {
|
||||
userInfoRepository.saveAndFlush(newUser);
|
||||
ret.setUsername(dbUserName);
|
||||
|
||||
return Optional.of(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -156,4 +155,13 @@ public class PowerJobLoginServiceImpl implements PowerJobAuthService {
|
||||
|
||||
return Optional.of(Long.parseLong(String.valueOf(userId)));
|
||||
}
|
||||
|
||||
private BizLoginService fetchBizLoginService(LoginContext loginContext) {
|
||||
final String loginType = loginContext.getLoginType();
|
||||
final BizLoginService loginService = type2LoginService.get(loginType);
|
||||
if (loginService == null) {
|
||||
throw new IllegalArgumentException("can't find LoginService by type: " + loginType);
|
||||
}
|
||||
return loginService;
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -1,21 +1,28 @@
|
||||
package tech.powerjob.server.web.controller;
|
||||
|
||||
import tech.powerjob.common.response.ResultDTO;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import tech.powerjob.server.persistence.remote.model.UserInfoDO;
|
||||
import tech.powerjob.server.persistence.remote.repository.UserInfoRepository;
|
||||
import tech.powerjob.server.core.service.UserService;
|
||||
import tech.powerjob.server.web.request.ModifyUserInfoRequest;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
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;
|
||||
|
||||
@ -28,21 +35,49 @@ import java.util.stream.Collectors;
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
public class UserInfoController {
|
||||
|
||||
@Resource
|
||||
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
|
||||
}
|
||||
|
||||
@GetMapping("/loginCallback")
|
||||
public ResultDTO<Void> loginCallback(HttpServletRequest httpServletRequest) {
|
||||
// 钉钉回调
|
||||
final String state = httpServletRequest.getParameter("state");
|
||||
if ("DingTalk".equalsIgnoreCase(state)) {
|
||||
// TODO: 钉钉服务
|
||||
loginContext.setLoginType("DingTalk");
|
||||
}
|
||||
// TODO: 承接登录回调功能
|
||||
return null;
|
||||
|
||||
final PowerJobUser powerJobUser = powerJobAuthService.tryLogin(loginContext);
|
||||
|
||||
httpServletResponse.addCookie(new Cookie("powerjob_token", powerJobUser.getJwtToken()));
|
||||
return ResultDTO.success(powerJobUser);
|
||||
}
|
||||
|
||||
@PostMapping("save")
|
||||
|
@ -0,0 +1,19 @@
|
||||
package tech.powerjob.server.web.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 用户登录请求
|
||||
*
|
||||
* @author tjq
|
||||
* @since 2023/3/26
|
||||
*/
|
||||
@Data
|
||||
public class UserLoginRequest implements Serializable {
|
||||
|
||||
private String type;
|
||||
|
||||
private String loginInfo;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user