Merge pull request #567 from dataease/pr@dev@feat_aksk_auth
feat: 使用ak,sk访问api接口以及swagger
This commit is contained in:
commit
a46cd75760
@ -2,18 +2,17 @@ package io.dataease.auth.config;
|
||||
|
||||
import io.dataease.auth.api.dto.CurrentRoleDto;
|
||||
import io.dataease.auth.api.dto.CurrentUserDto;
|
||||
import io.dataease.auth.entity.ASKToken;
|
||||
import io.dataease.auth.entity.JWTToken;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.handler.ApiKeyHandler;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.commons.utils.BeanUtils;
|
||||
import io.dataease.commons.utils.LogUtil;
|
||||
import io.dataease.listener.util.CacheUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.AuthenticationInfo;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.authc.SimpleAuthenticationInfo;
|
||||
import org.apache.shiro.authc.*;
|
||||
import org.apache.shiro.authz.AuthorizationInfo;
|
||||
import org.apache.shiro.authz.SimpleAuthorizationInfo;
|
||||
import org.apache.shiro.realm.AuthorizingRealm;
|
||||
@ -37,7 +36,7 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
|
||||
@Override
|
||||
public boolean supports(AuthenticationToken token) {
|
||||
return token instanceof JWTToken;
|
||||
return token instanceof JWTToken || token instanceof ASKToken;
|
||||
}
|
||||
|
||||
//验证资源权限
|
||||
@ -56,12 +55,27 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
|
||||
@Override
|
||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
|
||||
|
||||
if (auth instanceof ASKToken) {
|
||||
|
||||
Object accessKey = auth.getPrincipal();
|
||||
Object signature = auth.getCredentials();
|
||||
Long userId = ApiKeyHandler.getUser(accessKey.toString(), signature.toString());
|
||||
|
||||
SysUserEntity userEntity = userWithId(userId);
|
||||
CurrentUserDto currentUserDto = queryCacheUserDto(userEntity);
|
||||
return new SimpleAuthenticationInfo(currentUserDto, signature, "f2cReam");
|
||||
}
|
||||
|
||||
|
||||
|
||||
try {
|
||||
CacheUtils.get("lic_info", "lic");
|
||||
}catch (Exception e) {
|
||||
LogUtil.error(e);
|
||||
throw new AuthenticationException("lic error");
|
||||
}
|
||||
|
||||
TokenInfo tokenInfo = null;
|
||||
String token = null;
|
||||
try {
|
||||
@ -78,13 +92,14 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
throw new AuthenticationException("token invalid");
|
||||
}
|
||||
// 使用缓存
|
||||
SysUserEntity user = authUserService.getUserById(userId);
|
||||
/*SysUserEntity user = authUserService.getUserById(userId);
|
||||
if (user == null) {
|
||||
throw new AuthenticationException("User didn't existed!");
|
||||
}
|
||||
if (user.getEnabled()==0) {
|
||||
throw new AuthenticationException("User is valid!");
|
||||
}
|
||||
}*/
|
||||
SysUserEntity user = userWithId(userId);
|
||||
String pass = null;
|
||||
try {
|
||||
pass = user.getPassword();
|
||||
@ -94,6 +109,29 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
if (! JWTUtils.verify(token, tokenInfo, pass)) {
|
||||
throw new AuthenticationException("Username or password error");
|
||||
}
|
||||
/*// 使用缓存
|
||||
List<CurrentRoleDto> currentRoleDtos = authUserService.roleInfos(user.getUserId());
|
||||
// 使用缓存
|
||||
List<String> permissions = authUserService.permissions(user.getUserId());
|
||||
CurrentUserDto currentUserDto = BeanUtils.copyBean(new CurrentUserDto(), user);
|
||||
currentUserDto.setRoles(currentRoleDtos);
|
||||
currentUserDto.setPermissions(permissions);*/
|
||||
CurrentUserDto currentUserDto = queryCacheUserDto(user);
|
||||
return new SimpleAuthenticationInfo(currentUserDto, token, "f2cReam");
|
||||
}
|
||||
|
||||
public SysUserEntity userWithId(Long userId) {
|
||||
SysUserEntity user = authUserService.getUserById(userId);
|
||||
if (user == null) {
|
||||
throw new AuthenticationException("User didn't existed!");
|
||||
}
|
||||
if (user.getEnabled()==0) {
|
||||
throw new AuthenticationException("User is valid!");
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public CurrentUserDto queryCacheUserDto(SysUserEntity user) {
|
||||
// 使用缓存
|
||||
List<CurrentRoleDto> currentRoleDtos = authUserService.roleInfos(user.getUserId());
|
||||
// 使用缓存
|
||||
@ -101,6 +139,6 @@ public class F2CRealm extends AuthorizingRealm {
|
||||
CurrentUserDto currentUserDto = BeanUtils.copyBean(new CurrentUserDto(), user);
|
||||
currentUserDto.setRoles(currentRoleDtos);
|
||||
currentUserDto.setPermissions(permissions);
|
||||
return new SimpleAuthenticationInfo(currentUserDto, token, "f2cReam");
|
||||
return currentUserDto;
|
||||
}
|
||||
}
|
||||
|
||||
25
backend/src/main/java/io/dataease/auth/entity/ASKToken.java
Normal file
25
backend/src/main/java/io/dataease/auth/entity/ASKToken.java
Normal file
@ -0,0 +1,25 @@
|
||||
package io.dataease.auth.entity;
|
||||
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
|
||||
public class ASKToken implements AuthenticationToken {
|
||||
|
||||
private String accessKey;
|
||||
|
||||
private String signature;
|
||||
|
||||
public ASKToken(String accessKey, String signature) {
|
||||
this.accessKey = accessKey;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return accessKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getCredentials() {
|
||||
return signature;
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,10 @@
|
||||
package io.dataease.auth.filter;
|
||||
|
||||
import io.dataease.auth.entity.ASKToken;
|
||||
import io.dataease.auth.entity.JWTToken;
|
||||
import io.dataease.auth.entity.SysUserEntity;
|
||||
import io.dataease.auth.entity.TokenInfo;
|
||||
import io.dataease.auth.handler.ApiKeyHandler;
|
||||
import io.dataease.auth.service.AuthUserService;
|
||||
import io.dataease.auth.util.JWTUtils;
|
||||
import io.dataease.commons.utils.CommonBeanFactory;
|
||||
@ -48,6 +50,18 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
@Override
|
||||
protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception {
|
||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||
|
||||
|
||||
if (ApiKeyHandler.isApiKeyCall(httpServletRequest)) {
|
||||
// Long userId = ApiKeyHandler.getUser(httpServletRequest);
|
||||
|
||||
ASKToken askToken = ApiKeyHandler.buildToken(httpServletRequest);
|
||||
|
||||
// UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userId.toString(), ApiKeyHandler.random);
|
||||
getSubject(request, response).login(askToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
String authorization = httpServletRequest.getHeader("Authorization");
|
||||
if (StringUtils.startsWith(authorization, "Basic")) {
|
||||
return false;
|
||||
@ -72,7 +86,10 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
|
||||
*/
|
||||
@Override
|
||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
|
||||
if (isLoginAttempt(request, response)) {
|
||||
// 先判断是不是api调用
|
||||
HttpServletRequest hRequest = (HttpServletRequest) request;
|
||||
|
||||
if (isLoginAttempt(request, response) || ApiKeyHandler.isApiKeyCall(hRequest)) {
|
||||
try {
|
||||
boolean loginSuccess = executeLogin(request, response);
|
||||
return loginSuccess;
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
package io.dataease.auth.handler;
|
||||
|
||||
import io.dataease.auth.entity.ASKToken;
|
||||
import io.dataease.commons.utils.CodingUtil;
|
||||
import io.dataease.plugins.config.SpringContextUtil;
|
||||
import io.dataease.plugins.xpack.ukey.dto.request.XpackUkeyDto;
|
||||
import io.dataease.plugins.xpack.ukey.service.UkeyXpackService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ApiKeyHandler {
|
||||
|
||||
public static final String API_ACCESS_KEY = "accessKey";
|
||||
|
||||
public static final String API_SIGNATURE = "signature";
|
||||
|
||||
|
||||
public static String random = UUID.randomUUID().toString() + UUID.randomUUID().toString();
|
||||
|
||||
public static Long getUser(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
return getUser(request.getHeader(API_ACCESS_KEY), request.getHeader(API_SIGNATURE));
|
||||
}
|
||||
|
||||
public static ASKToken buildToken(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return null;
|
||||
}
|
||||
String accessKey = request.getHeader(API_ACCESS_KEY);
|
||||
String signature = request.getHeader(API_SIGNATURE);
|
||||
ASKToken askToken = new ASKToken(accessKey, signature);
|
||||
return askToken;
|
||||
}
|
||||
|
||||
public static Boolean isApiKeyCall(HttpServletRequest request) {
|
||||
if (request == null) {
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isBlank(request.getHeader(API_ACCESS_KEY)) || StringUtils.isBlank(request.getHeader(API_SIGNATURE))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static XpackUkeyDto ukey(String accessKey) {
|
||||
UkeyXpackService ukeyXpackService = SpringContextUtil.getBean(UkeyXpackService.class);
|
||||
XpackUkeyDto userKey = ukeyXpackService.getUserKey(accessKey);
|
||||
return userKey;
|
||||
}
|
||||
|
||||
public static Long getUser(String accessKey, String signature) {
|
||||
if (StringUtils.isBlank(accessKey) || StringUtils.isBlank(signature)) {
|
||||
return null;
|
||||
}
|
||||
XpackUkeyDto userKey = ukey(accessKey);
|
||||
if (userKey == null) {
|
||||
throw new RuntimeException("invalid accessKey");
|
||||
}
|
||||
String signatureDecrypt;
|
||||
try {
|
||||
signatureDecrypt = CodingUtil.aesDecrypt(signature, userKey.getSecretKey(), accessKey);
|
||||
} catch (Throwable t) {
|
||||
throw new RuntimeException("invalid signature");
|
||||
}
|
||||
String[] signatureArray = StringUtils.split(StringUtils.trimToNull(signatureDecrypt), "|");
|
||||
if (signatureArray.length < 2) {
|
||||
throw new RuntimeException("invalid signature");
|
||||
}
|
||||
if (!StringUtils.equals(accessKey, signatureArray[0])) {
|
||||
throw new RuntimeException("invalid signature");
|
||||
}
|
||||
long signatureTime = 0l;
|
||||
try {
|
||||
signatureTime = Long.valueOf(signatureArray[signatureArray.length - 1]).longValue();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (Math.abs(System.currentTimeMillis() - signatureTime) > 1800000) {
|
||||
//签名30分钟超时
|
||||
throw new RuntimeException("expired signature");
|
||||
}
|
||||
return userKey.getUserId();
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ import javax.crypto.*;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 加密解密工具
|
||||
@ -153,6 +154,17 @@ public class CodingUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/*public static String getSignature(String accessKey, String secretKey) throws Exception {
|
||||
return aesEncrypt(accessKey + "|" + UUID.randomUUID().toString() + "|" + System.currentTimeMillis(), secretKey, accessKey);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception{
|
||||
String accessKey = "gnPFmtAsdLhUEWPA";
|
||||
String secretKey = "TfK5FGUle0KRfJJJ";
|
||||
String signature = getSignature(accessKey, secretKey);
|
||||
System.out.println(signature);
|
||||
}*/
|
||||
|
||||
public static String secretKey() {
|
||||
try {
|
||||
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
|
||||
|
||||
@ -77,7 +77,9 @@ public class Knife4jConfiguration {
|
||||
|
||||
private Docket defaultApi(String groupName, String packageName) {
|
||||
List<SecurityScheme> securitySchemes=new ArrayList<>();
|
||||
securitySchemes.add(apiKey());
|
||||
securitySchemes.add(accessKey());
|
||||
securitySchemes.add(signature());
|
||||
|
||||
List<SecurityContext> securityContexts = new ArrayList<>();
|
||||
securityContexts.add(securityContext());
|
||||
|
||||
@ -100,8 +102,12 @@ public class Knife4jConfiguration {
|
||||
.build();
|
||||
}
|
||||
|
||||
private ApiKey apiKey() {
|
||||
return new ApiKey("Authorization", "Authorization", "header");
|
||||
private ApiKey accessKey() {
|
||||
return new ApiKey("accessKey", "accessKey", "header");
|
||||
}
|
||||
|
||||
private ApiKey signature() {
|
||||
return new ApiKey("signature", "signature", "header");
|
||||
}
|
||||
|
||||
|
||||
@ -109,7 +115,12 @@ public class Knife4jConfiguration {
|
||||
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
|
||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
|
||||
authorizationScopes[0] = authorizationScope;
|
||||
return CollectionUtil.newArrayList(new SecurityReference("Authorization", authorizationScopes));
|
||||
|
||||
List<SecurityReference> results = new ArrayList<>();
|
||||
results.add(new SecurityReference("accessKey", authorizationScopes));
|
||||
results.add(new SecurityReference("signature", authorizationScopes));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ knife4j.enable=true
|
||||
knife4j.setting.enableFooter=false
|
||||
knife4j.setting.enableFooterCustom=false
|
||||
knife4j.setting.footerCustomContent=fit2cloud 1.0-b9
|
||||
knife4j.setting.enableSwaggerModels=false
|
||||
#knife4j.setting.enableSwaggerModels=false
|
||||
knife4j.setting.enableDocumentManage=false
|
||||
knife4j.setting.enableSearch=false
|
||||
knife4j.setting.enableOpenApi=false
|
||||
|
||||
Loading…
Reference in New Issue
Block a user