mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: PowerJobAuthInterceptor
This commit is contained in:
parent
926c8758ed
commit
ce6c62f786
@ -0,0 +1,18 @@
|
|||||||
|
package tech.powerjob.common;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一定义日志
|
||||||
|
*
|
||||||
|
* @author tjq
|
||||||
|
* @since 2023/3/25
|
||||||
|
*/
|
||||||
|
public class Loggers {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Web 层统一日志
|
||||||
|
*/
|
||||||
|
public static final Logger WEB = LoggerFactory.getLogger("P_SERVER_LOGGER_WEB");
|
||||||
|
}
|
@ -1,7 +1,8 @@
|
|||||||
package tech.powerjob.server.auth.login;
|
package tech.powerjob.server.auth;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
|
@Accessors(chain = true)
|
||||||
public class LoginContext {
|
public class LoginContext {
|
||||||
|
|
||||||
private HttpServletRequest httpServletRequest;
|
private HttpServletRequest httpServletRequest;
|
@ -2,12 +2,19 @@ package tech.powerjob.server.auth.anno;
|
|||||||
|
|
||||||
import tech.powerjob.server.auth.Permission;
|
import tech.powerjob.server.auth.Permission;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* API 权限
|
* API 权限
|
||||||
*
|
*
|
||||||
* @author tjq
|
* @author tjq
|
||||||
* @since 2023/3/20
|
* @since 2023/3/20
|
||||||
*/
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface ApiPermission {
|
public @interface ApiPermission {
|
||||||
/**
|
/**
|
||||||
* API 名称
|
* API 名称
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
package tech.powerjob.server.auth.interceptor;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
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.PowerJobUser;
|
||||||
|
import tech.powerjob.server.auth.anno.ApiPermission;
|
||||||
|
import tech.powerjob.server.auth.service.PowerJobAuthService;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* login auth and permission check
|
||||||
|
*
|
||||||
|
* @author tjq
|
||||||
|
* @since 2023/3/25
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class PowerJobAuthInterceptor implements HandlerInterceptor {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private PowerJobAuthService powerJobAuthService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean preHandle(@NonNull HttpServletRequest request,@NonNull HttpServletResponse response,@NonNull Object handler) throws Exception {
|
||||||
|
if (!(handler instanceof HandlerMethod)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||||
|
final Method method = handlerMethod.getMethod();
|
||||||
|
final ApiPermission apiPermissionAnno = method.getAnnotation(ApiPermission.class);
|
||||||
|
|
||||||
|
// 无注解代表不需要权限,无需登陆直接访问
|
||||||
|
if (apiPermissionAnno == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试直接解析登陆
|
||||||
|
final Optional<PowerJobUser> loginUserOpt = powerJobAuthService.parse(request);
|
||||||
|
|
||||||
|
// 未登录前先使用302重定向到登录页面
|
||||||
|
if (!loginUserOpt.isPresent()) {
|
||||||
|
response.setStatus(302);
|
||||||
|
response.setHeader("location", request.getContextPath() + "/login");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登陆用户进行权限校验
|
||||||
|
final PowerJobUser powerJobUser = loginUserOpt.get();
|
||||||
|
final boolean hasPermission = powerJobAuthService.hasPermission(powerJobUser, apiPermissionAnno);
|
||||||
|
if (hasPermission) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String resourceName = parseResourceName(apiPermissionAnno, handlerMethod);
|
||||||
|
Loggers.WEB.info("[PowerJobAuthInterceptor] user[{}] has no permission to access: {}", powerJobUser.getUsername(), resourceName);
|
||||||
|
|
||||||
|
throw new PowerJobException("Permission denied!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String parseResourceName(ApiPermission apiPermission, HandlerMethod handlerMethod) {
|
||||||
|
final String name = apiPermission.name();
|
||||||
|
if (StringUtils.isNotEmpty(name)) {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final String clzName = handlerMethod.getBean().getClass().getSimpleName();
|
||||||
|
final String methodName = handlerMethod.getMethod().getName();
|
||||||
|
return String.format("%s_%s", clzName, methodName);
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package tech.powerjob.server.auth.login.biz;
|
package tech.powerjob.server.auth.login;
|
||||||
|
|
||||||
import tech.powerjob.server.auth.login.LoginContext;
|
import tech.powerjob.server.auth.LoginContext;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package tech.powerjob.server.auth.login.biz;
|
package tech.powerjob.server.auth.login;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
@ -1,12 +1,12 @@
|
|||||||
package tech.powerjob.server.auth.login.biz.impl;
|
package tech.powerjob.server.auth.login.impl;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.powerjob.common.Loggers;
|
||||||
import tech.powerjob.common.utils.DigestUtils;
|
import tech.powerjob.common.utils.DigestUtils;
|
||||||
import tech.powerjob.server.auth.login.LoginContext;
|
import tech.powerjob.server.auth.LoginContext;
|
||||||
import tech.powerjob.server.auth.login.biz.BizLoginService;
|
import tech.powerjob.server.auth.login.BizLoginService;
|
||||||
import tech.powerjob.server.auth.login.biz.BizUser;
|
import tech.powerjob.server.auth.login.BizUser;
|
||||||
import tech.powerjob.server.common.SJ;
|
import tech.powerjob.server.common.SJ;
|
||||||
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;
|
||||||
@ -21,7 +21,6 @@ import java.util.Optional;
|
|||||||
* @author tjq
|
* @author tjq
|
||||||
* @since 2023/3/20
|
* @since 2023/3/20
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
|
||||||
@Service
|
@Service
|
||||||
public class DefaultBizLoginService implements BizLoginService {
|
public class DefaultBizLoginService implements BizLoginService {
|
||||||
|
|
||||||
@ -51,13 +50,13 @@ public class DefaultBizLoginService implements BizLoginService {
|
|||||||
final String password = loginInfoMap.get(KEY_PASSWORD);
|
final String password = loginInfoMap.get(KEY_PASSWORD);
|
||||||
|
|
||||||
if (StringUtils.isAnyEmpty(username, password)) {
|
if (StringUtils.isAnyEmpty(username, password)) {
|
||||||
log.debug("[DefaultBizLoginService] username or password is empty, login failed!");
|
Loggers.WEB.debug("[DefaultBizLoginService] username or password is empty, login failed!");
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
final Optional<UserInfoDO> userInfoOpt = userInfoRepository.findByUsername(username);
|
final Optional<UserInfoDO> userInfoOpt = userInfoRepository.findByUsername(username);
|
||||||
if (!userInfoOpt.isPresent()) {
|
if (!userInfoOpt.isPresent()) {
|
||||||
log.debug("[DefaultBizLoginService] can't find user by username: {}", username);
|
Loggers.WEB.debug("[DefaultBizLoginService] can't find user by username: {}", username);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ public class DefaultBizLoginService implements BizLoginService {
|
|||||||
return Optional.of(bizUser);
|
return Optional.of(bizUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("[DefaultBizLoginService] user[{}]'s password is not correct, login failed!", username);
|
Loggers.WEB.debug("[DefaultBizLoginService] user[{}]'s password is not correct, login failed!", username);
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,10 @@
|
|||||||
package tech.powerjob.server.auth.login;
|
package tech.powerjob.server.auth.service;
|
||||||
|
|
||||||
|
import tech.powerjob.server.auth.LoginContext;
|
||||||
import tech.powerjob.server.auth.PowerJobUser;
|
import tech.powerjob.server.auth.PowerJobUser;
|
||||||
|
import tech.powerjob.server.auth.anno.ApiPermission;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,7 +13,7 @@ import java.util.Optional;
|
|||||||
* @author tjq
|
* @author tjq
|
||||||
* @since 2023/3/21
|
* @since 2023/3/21
|
||||||
*/
|
*/
|
||||||
public interface PowerJobLoginService {
|
public interface PowerJobAuthService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行真正的登陆操作
|
* 执行真正的登陆操作
|
||||||
@ -24,5 +27,7 @@ public interface PowerJobLoginService {
|
|||||||
* @param loginContext 登录上下文
|
* @param loginContext 登录上下文
|
||||||
* @return PowerJob 用户
|
* @return PowerJob 用户
|
||||||
*/
|
*/
|
||||||
Optional<PowerJobUser> parse(LoginContext loginContext);
|
Optional<PowerJobUser> parse(HttpServletRequest httpServletRequest);
|
||||||
|
|
||||||
|
boolean hasPermission(PowerJobUser user, ApiPermission apiPermission);
|
||||||
}
|
}
|
@ -1,14 +1,16 @@
|
|||||||
package tech.powerjob.server.auth.login;
|
package tech.powerjob.server.auth.service;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
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.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import tech.powerjob.common.Loggers;
|
||||||
|
import tech.powerjob.server.auth.LoginContext;
|
||||||
import tech.powerjob.server.auth.PowerJobUser;
|
import tech.powerjob.server.auth.PowerJobUser;
|
||||||
import tech.powerjob.server.auth.login.biz.BizLoginService;
|
import tech.powerjob.server.auth.anno.ApiPermission;
|
||||||
import tech.powerjob.server.auth.login.biz.BizUser;
|
import tech.powerjob.server.auth.login.BizLoginService;
|
||||||
|
import tech.powerjob.server.auth.login.BizUser;
|
||||||
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;
|
||||||
|
|
||||||
@ -23,9 +25,8 @@ import java.util.Optional;
|
|||||||
* @author tjq
|
* @author tjq
|
||||||
* @since 2023/3/21
|
* @since 2023/3/21
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
|
||||||
@Service
|
@Service
|
||||||
public class PowerJobLoginServiceImpl implements PowerJobLoginService {
|
public class PowerJobLoginServiceImpl implements PowerJobAuthService {
|
||||||
|
|
||||||
private final UserInfoRepository userInfoRepository;
|
private final UserInfoRepository userInfoRepository;
|
||||||
private final Map<String, BizLoginService> type2LoginService = Maps.newHashMap();
|
private final Map<String, BizLoginService> type2LoginService = Maps.newHashMap();
|
||||||
@ -67,7 +68,7 @@ public class PowerJobLoginServiceImpl implements PowerJobLoginService {
|
|||||||
// 同步在 PowerJob 用户库创建该用户
|
// 同步在 PowerJob 用户库创建该用户
|
||||||
UserInfoDO newUser = new UserInfoDO();
|
UserInfoDO newUser = new UserInfoDO();
|
||||||
newUser.setUsername(dbUserName);
|
newUser.setUsername(dbUserName);
|
||||||
log.info("[PowerJobLoginService] sync user to PowerJobUserSystem: {}", dbUserName);
|
Loggers.WEB.info("[PowerJobLoginService] sync user to PowerJobUserSystem: {}", dbUserName);
|
||||||
userInfoRepository.saveAndFlush(newUser);
|
userInfoRepository.saveAndFlush(newUser);
|
||||||
ret.setUsername(dbUserName);
|
ret.setUsername(dbUserName);
|
||||||
|
|
||||||
@ -75,9 +76,9 @@ public class PowerJobLoginServiceImpl implements PowerJobLoginService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<PowerJobUser> parse(LoginContext loginContext) {
|
public Optional<PowerJobUser> parse(HttpServletRequest httpServletRequest) {
|
||||||
|
|
||||||
final Optional<String> usernameOpt = parseUsername(loginContext);
|
final Optional<String> usernameOpt = parseUsername(httpServletRequest);
|
||||||
if (!usernameOpt.isPresent()) {
|
if (!usernameOpt.isPresent()) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
@ -88,8 +89,12 @@ public class PowerJobLoginServiceImpl implements PowerJobLoginService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<String> parseUsername(LoginContext loginContext) {
|
@Override
|
||||||
final HttpServletRequest httpServletRequest = loginContext.getHttpServletRequest();
|
public boolean hasPermission(PowerJobUser user, ApiPermission apiPermission) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<String> parseUsername(HttpServletRequest httpServletRequest) {
|
||||||
final String tokenHeader = httpServletRequest.getHeader(TOKEN_HEADER_NAME);
|
final String tokenHeader = httpServletRequest.getHeader(TOKEN_HEADER_NAME);
|
||||||
if (StringUtils.isEmpty(tokenHeader)) {
|
if (StringUtils.isEmpty(tokenHeader)) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
Loading…
x
Reference in New Issue
Block a user