Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
D
dataease
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
njgzx
dataease
Commits
c03b82fd
Unverified
提交
c03b82fd
authored
9月 14, 2021
作者:
fit2cloud-chenyw
提交者:
GitHub
9月 14, 2021
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #813 from dataease/pr@dev@feat_oidc_sso_login
feat: sso单点登录
上级
bc2b980f
5f20b3fc
隐藏空白字符变更
内嵌
并排
正在显示
20 个修改的文件
包含
491 行增加
和
54 行删除
+491
-54
pom.xml
backend/pom.xml
+2
-2
AuthApi.java
backend/src/main/java/io/dataease/auth/api/AuthApi.java
+5
-2
TokenInfo.java
backend/src/main/java/io/dataease/auth/entity/TokenInfo.java
+2
-0
F2CLogoutFilter.java
...rc/main/java/io/dataease/auth/filter/F2CLogoutFilter.java
+0
-1
AuthServer.java
...end/src/main/java/io/dataease/auth/server/AuthServer.java
+19
-1
AuthUserService.java
...c/main/java/io/dataease/auth/service/AuthUserService.java
+2
-0
AuthUserServiceImpl.java
...va/io/dataease/auth/service/impl/AuthUserServiceImpl.java
+13
-0
ShiroServiceImpl.java
.../java/io/dataease/auth/service/impl/ShiroServiceImpl.java
+7
-1
JWTUtils.java
backend/src/main/java/io/dataease/auth/util/JWTUtils.java
+22
-10
LoadjarUtil.java
...src/main/java/io/dataease/plugins/config/LoadjarUtil.java
+8
-0
ControllerLoader.java
...ain/java/io/dataease/plugins/loader/ControllerLoader.java
+95
-0
ModuleClassLoader.java
...in/java/io/dataease/plugins/loader/ModuleClassLoader.java
+25
-1
PluginCommonServer.java
...n/java/io/dataease/plugins/server/PluginCommonServer.java
+39
-2
SSOServer.java
...d/src/main/java/io/dataease/plugins/server/SSOServer.java
+85
-0
XOidcServer.java
...src/main/java/io/dataease/plugins/server/XOidcServer.java
+33
-1
SysUserService.java
...src/main/java/io/dataease/service/sys/SysUserService.java
+32
-0
user.js
frontend/src/api/user.js
+7
-0
index.vue
frontend/src/views/login/index.vue
+25
-32
PluginCom.vue
frontend/src/views/system/plugin/PluginCom.vue
+69
-0
index.vue
frontend/src/views/system/user/index.vue
+1
-1
没有找到文件。
backend/pom.xml
浏览文件 @
c03b82fd
...
...
@@ -252,11 +252,11 @@
<version>
20171018
</version>
</dependency>
<dependency>
<
!--<
dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
</dependency>
-->
<!-- 反射工具包 -->
<dependency>
<groupId>
net.oneandone.reflections8
</groupId>
...
...
backend/src/main/java/io/dataease/auth/api/AuthApi.java
浏览文件 @
c03b82fd
...
...
@@ -4,9 +4,7 @@ import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import
io.dataease.auth.api.dto.CurrentUserDto
;
import
io.dataease.auth.api.dto.LoginDto
;
import
io.swagger.annotations.Api
;
import
io.swagger.annotations.ApiModelProperty
;
import
io.swagger.annotations.ApiOperation
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
...
...
@@ -46,4 +44,9 @@ public interface AuthApi {
@PostMapping
(
"/isOpenLdap"
)
boolean
isOpenLdap
();
@ApiOperation
(
"是否开启oidc"
)
@PostMapping
(
"/isOpenOidc"
)
boolean
isOpenOidc
();
}
backend/src/main/java/io/dataease/auth/entity/TokenInfo.java
浏览文件 @
c03b82fd
...
...
@@ -13,6 +13,8 @@ public class TokenInfo implements Serializable {
private
Long
userId
;
/* private String idToken; */
public
String
format
(){
return
username
+
","
+
userId
;
}
...
...
backend/src/main/java/io/dataease/auth/filter/F2CLogoutFilter.java
浏览文件 @
c03b82fd
...
...
@@ -4,7 +4,6 @@ import org.apache.shiro.subject.Subject;
import
org.apache.shiro.web.filter.authc.LogoutFilter
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
javax.servlet.ServletRequest
;
import
javax.servlet.ServletResponse
;
...
...
backend/src/main/java/io/dataease/auth/server/AuthServer.java
浏览文件 @
c03b82fd
...
...
@@ -21,17 +21,19 @@ import io.dataease.plugins.util.PluginUtils;
import
io.dataease.plugins.xpack.ldap.dto.request.LdapValidateRequest
;
import
io.dataease.plugins.xpack.ldap.dto.response.ValidateResult
;
import
io.dataease.plugins.xpack.ldap.service.LdapXpackService
;
import
io.dataease.plugins.xpack.oidc.service.OidcXpackService
;
import
org.apache.commons.lang3.ObjectUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.shiro.SecurityUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RestController
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
javax.servlet.http.HttpServletRequest
;
@RestController
public
class
AuthServer
implements
AuthApi
{
...
...
@@ -113,6 +115,13 @@ public class AuthServer implements AuthApi {
@Override
public
String
logout
()
{
String
token
=
ServletUtils
.
getToken
();
if
(
isOpenOidc
())
{
HttpServletRequest
request
=
ServletUtils
.
request
();
String
idToken
=
request
.
getHeader
(
"IdToken"
);
OidcXpackService
oidcXpackService
=
SpringContextUtil
.
getBean
(
OidcXpackService
.
class
);
oidcXpackService
.
logout
(
idToken
);
}
if
(
StringUtils
.
isEmpty
(
token
)
||
StringUtils
.
equals
(
"null"
,
token
)
||
StringUtils
.
equals
(
"undefined"
,
token
))
{
return
"success"
;
}
...
...
@@ -144,6 +153,15 @@ public class AuthServer implements AuthApi {
return
open
;
}
@Override
public
boolean
isOpenOidc
()
{
Boolean
licValid
=
PluginUtils
.
licValid
();
if
(!
licValid
)
return
false
;
return
authUserService
.
supportOidc
();
}
/*@Override
public Boolean isLogin() {
return null;
...
...
backend/src/main/java/io/dataease/auth/service/AuthUserService.java
浏览文件 @
c03b82fd
...
...
@@ -23,6 +23,8 @@ public interface AuthUserService {
boolean
supportLdap
();
Boolean
supportOidc
();
}
backend/src/main/java/io/dataease/auth/service/impl/AuthUserServiceImpl.java
浏览文件 @
c03b82fd
...
...
@@ -10,6 +10,8 @@ import io.dataease.commons.constants.AuthConstants;
import
io.dataease.commons.utils.LogUtil
;
import
io.dataease.plugins.config.SpringContextUtil
;
import
io.dataease.plugins.xpack.ldap.service.LdapXpackService
;
import
io.dataease.plugins.xpack.oidc.service.OidcXpackService
;
import
org.apache.commons.lang3.ObjectUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.cache.annotation.CacheEvict
;
...
...
@@ -114,4 +116,15 @@ public class AuthUserServiceImpl implements AuthUserService {
if
(
ObjectUtils
.
isEmpty
(
ldapXpackService
))
return
false
;
return
ldapXpackService
.
isOpen
();
}
@Override
public
Boolean
supportOidc
()
{
Map
<
String
,
OidcXpackService
>
beansOfType
=
SpringContextUtil
.
getApplicationContext
().
getBeansOfType
((
OidcXpackService
.
class
));
if
(
beansOfType
.
keySet
().
size
()
==
0
)
return
false
;
OidcXpackService
oidcXpackService
=
SpringContextUtil
.
getBean
(
OidcXpackService
.
class
);
if
(
ObjectUtils
.
isEmpty
(
oidcXpackService
))
return
false
;
return
oidcXpackService
.
isSuuportOIDC
();
}
}
backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
浏览文件 @
c03b82fd
...
...
@@ -56,9 +56,15 @@ public class ShiroServiceImpl implements ShiroService {
// filterChainDefinitionMap.put("/axios.map", ANON);
filterChainDefinitionMap
.
put
(
"/api/auth/login"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/api/auth/logout"
,
ANON
);
//
filterChainDefinitionMap.put("/api/auth/logout", ANON);
filterChainDefinitionMap
.
put
(
"/api/auth/validateName"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/api/auth/isOpenLdap"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/api/auth/isOpenOidc"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/api/pluginCommon/component/*"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/plugin/oidc/authInfo"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/sso/callBack*"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/unauth"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/display/**"
,
ANON
);
filterChainDefinitionMap
.
put
(
"/tokenExpired"
,
ANON
);
...
...
backend/src/main/java/io/dataease/auth/util/JWTUtils.java
浏览文件 @
c03b82fd
...
...
@@ -2,16 +2,18 @@ package io.dataease.auth.util;
import
com.auth0.jwt.JWT
;
import
com.auth0.jwt.JWTVerifier
;
import
com.auth0.jwt.JWTCreator.Builder
;
import
com.auth0.jwt.algorithms.Algorithm
;
import
com.auth0.jwt.exceptions.JWTDecodeException
;
import
com.auth0.jwt.interfaces.DecodedJWT
;
import
com.auth0.jwt.interfaces.Verification
;
import
io.dataease.auth.entity.TokenInfo
;
import
io.dataease.auth.entity.TokenInfo.TokenInfoBuilder
;
import
io.dataease.commons.utils.CommonBeanFactory
;
import
io.dataease.exception.DataEaseException
;
import
org.apache.commons.lang3.ObjectUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.core.env.Environment
;
import
java.util.Date
;
...
...
@@ -34,10 +36,13 @@ public class JWTUtils {
*/
public
static
boolean
verify
(
String
token
,
TokenInfo
tokenInfo
,
String
secret
)
{
Algorithm
algorithm
=
Algorithm
.
HMAC256
(
secret
);
JWTVerifier
verifier
=
JWT
.
require
(
algorithm
)
Verification
verification
=
JWT
.
require
(
algorithm
)
.
withClaim
(
"username"
,
tokenInfo
.
getUsername
())
.
withClaim
(
"userId"
,
tokenInfo
.
getUserId
())
.
build
();
.
withClaim
(
"userId"
,
tokenInfo
.
getUserId
());
/* if (StringUtils.isNotBlank(tokenInfo.getIdToken())) {
verification.withClaim("idToken", tokenInfo.getIdToken());
} */
JWTVerifier
verifier
=
verification
.
build
();
verifier
.
verify
(
token
);
return
true
;
}
...
...
@@ -50,10 +55,15 @@ public class JWTUtils {
DecodedJWT
jwt
=
JWT
.
decode
(
token
);
String
username
=
jwt
.
getClaim
(
"username"
).
asString
();
Long
userId
=
jwt
.
getClaim
(
"userId"
).
asLong
();
// String idToken = jwt.getClaim("idToken").asString();
if
(
StringUtils
.
isEmpty
(
username
)
||
ObjectUtils
.
isEmpty
(
userId
)
){
DataEaseException
.
throwException
(
"token格式错误!"
);
}
TokenInfo
tokenInfo
=
TokenInfo
.
builder
().
username
(
username
).
userId
(
userId
).
build
();
TokenInfoBuilder
tokenInfoBuilder
=
TokenInfo
.
builder
().
username
(
username
).
userId
(
userId
);
/* if (StringUtils.isNotBlank(idToken)) {
tokenInfoBuilder.idToken(idToken);
} */
TokenInfo
tokenInfo
=
tokenInfoBuilder
.
build
();
return
tokenInfo
;
}
...
...
@@ -107,12 +117,14 @@ public class JWTUtils {
try
{
Date
date
=
new
Date
(
System
.
currentTimeMillis
()+
EXPIRE_TIME
);
Algorithm
algorithm
=
Algorithm
.
HMAC256
(
secret
);
// 附带username信息
return
JWT
.
create
()
Builder
builder
=
JWT
.
create
()
.
withClaim
(
"username"
,
tokenInfo
.
getUsername
())
.
withClaim
(
"userId"
,
tokenInfo
.
getUserId
())
.
withExpiresAt
(
date
)
.
sign
(
algorithm
);
.
withClaim
(
"userId"
,
tokenInfo
.
getUserId
());
/* if (StringUtils.isNotBlank(tokenInfo.getIdToken())) {
builder.withClaim("idToken", tokenInfo.getIdToken());
} */
return
builder
.
withExpiresAt
(
date
).
sign
(
algorithm
);
}
catch
(
Exception
e
)
{
return
null
;
}
...
...
backend/src/main/java/io/dataease/plugins/config/LoadjarUtil.java
浏览文件 @
c03b82fd
...
...
@@ -2,6 +2,7 @@ package io.dataease.plugins.config;
import
io.dataease.base.domain.MyPlugin
;
import
io.dataease.plugins.loader.ClassloaderResponsity
;
import
io.dataease.plugins.loader.ControllerLoader
;
import
io.dataease.plugins.loader.ModuleClassLoader
;
import
io.dataease.plugins.loader.MybatisLoader
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
...
@@ -19,6 +20,9 @@ public class LoadjarUtil {
@Autowired
private
MybatisLoader
mybatisLoader
;
@Autowired
private
ControllerLoader
controllerLoader
;
public
List
<?>
loadJar
(
String
jarPath
,
MyPlugin
myPlugin
)
throws
Exception
{
File
jar
=
new
File
(
jarPath
);
URI
uri
=
jar
.
toURI
();
...
...
@@ -34,6 +38,10 @@ public class LoadjarUtil {
Thread
.
currentThread
().
setContextClassLoader
(
classLoader
);
classLoader
.
initBean
();
mybatisLoader
.
loadMybatis
(
myPlugin
);
List
<
String
>
controllers
=
classLoader
.
getRegisteredController
();
controllerLoader
.
registerController
(
controllers
);
ClassloaderResponsity
.
getInstance
().
addClassLoader
(
moduleName
,
classLoader
);
...
...
backend/src/main/java/io/dataease/plugins/loader/ControllerLoader.java
0 → 100644
浏览文件 @
c03b82fd
package
io
.
dataease
.
plugins
.
loader
;
import
io.dataease.commons.utils.LogUtil
;
import
io.dataease.plugins.config.SpringContextUtil
;
import
org.springframework.stereotype.Component
;
import
org.springframework.util.ClassUtils
;
import
org.springframework.util.ReflectionUtils
;
import
org.springframework.web.servlet.mvc.method.RequestMappingInfo
;
import
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
;
import
java.lang.reflect.Method
;
import
java.util.List
;
@Component
public
class
ControllerLoader
{
/**
* 去掉Controller的Mapping
* @param controllerBeanName
*/
private
void
unregisterController
(
String
controllerBeanName
){
final
RequestMappingHandlerMapping
requestMappingHandlerMapping
=(
RequestMappingHandlerMapping
)
SpringContextUtil
.
getBean
(
"requestMappingHandlerMapping"
);
if
(
requestMappingHandlerMapping
!=
null
){
String
handler
=
controllerBeanName
;
Object
controller
=
SpringContextUtil
.
getBean
(
handler
);
if
(
controller
==
null
){
return
;
}
final
Class
<?>
targetClass
=
controller
.
getClass
();
ReflectionUtils
.
doWithMethods
(
targetClass
,
new
ReflectionUtils
.
MethodCallback
()
{
public
void
doWith
(
Method
method
)
{
Method
specificMethod
=
ClassUtils
.
getMostSpecificMethod
(
method
,
targetClass
);
try
{
Method
createMappingMethod
=
RequestMappingHandlerMapping
.
class
.
getDeclaredMethod
(
"getMappingForMethod"
,
Method
.
class
,
Class
.
class
);
createMappingMethod
.
setAccessible
(
true
);
RequestMappingInfo
requestMappingInfo
=(
RequestMappingInfo
)
createMappingMethod
.
invoke
(
requestMappingHandlerMapping
,
specificMethod
,
targetClass
);
if
(
requestMappingInfo
!=
null
)
{
requestMappingHandlerMapping
.
unregisterMapping
(
requestMappingInfo
);
}
}
catch
(
Exception
e
){
e
.
printStackTrace
();
}
}
},
ReflectionUtils
.
USER_DECLARED_METHODS
);
}
}
/**
* 注册Controller
* @param controllerBeanName
* @throws Exception
*/
private
void
registerController
(
String
controllerBeanName
)
throws
Exception
{
final
RequestMappingHandlerMapping
requestMappingHandlerMapping
=(
RequestMappingHandlerMapping
)
SpringContextUtil
.
getBean
(
"requestMappingHandlerMapping"
);
if
(
requestMappingHandlerMapping
!=
null
){
String
handler
=
controllerBeanName
;
Object
controller
=
SpringContextUtil
.
getBean
(
handler
);
if
(
controller
==
null
){
return
;
}
unregisterController
(
controllerBeanName
);
//注册Controller
Method
method
=
requestMappingHandlerMapping
.
getClass
().
getSuperclass
().
getSuperclass
().
getDeclaredMethod
(
"detectHandlerMethods"
,
Object
.
class
);
method
.
setAccessible
(
true
);
method
.
invoke
(
requestMappingHandlerMapping
,
handler
);
}
}
public
void
registerController
(
List
<
String
>
beanNames
)
{
beanNames
.
forEach
(
name
->
{
try
{
registerController
(
name
);
}
catch
(
Exception
e
)
{
// e.printStackTrace();
LogUtil
.
error
(
e
);
}
});
}
}
backend/src/main/java/io/dataease/plugins/loader/ModuleClassLoader.java
浏览文件 @
c03b82fd
...
...
@@ -7,10 +7,14 @@ import org.apache.ibatis.session.SqlSessionFactory;
import
org.apache.ibatis.type.TypeAliasRegistry
;
import
org.springframework.beans.factory.config.BeanDefinition
;
import
org.springframework.beans.factory.support.BeanDefinitionBuilder
;
import
org.springframework.core.annotation.AnnotatedElementUtils
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.stereotype.Repository
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.StringUtils
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
java.io.ByteArrayOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
...
...
@@ -35,6 +39,8 @@ public class ModuleClassLoader extends URLClassLoader {
//需要注册的spring bean的name集合
private
List
<
String
>
registeredBean
=
new
ArrayList
<>();
private
List
<
String
>
registeredController
=
new
ArrayList
<>();
//构造
public
ModuleClassLoader
(
URL
[]
urls
,
ClassLoader
parent
)
{
...
...
@@ -150,8 +156,12 @@ public class ModuleClassLoader extends URLClassLoader {
beanName
=
StringUtils
.
uncapitalize
(
beanName
);
SpringContextUtil
.
getBeanFactory
().
registerBeanDefinition
(
beanName
,
beanDefinition
);
if
(
isHandler
(
cla
))
{
registeredController
.
add
(
beanName
);
}
registeredBean
.
add
(
beanName
);
// System.out.println("注册bean:"+beanName);
}
}
...
...
@@ -164,6 +174,10 @@ public class ModuleClassLoader extends URLClassLoader {
return
registeredBean
;
}
public
List
<
String
>
getRegisteredController
()
{
return
registeredController
;
}
/**
* 方法描述 判断class对象是否带有spring的注解
...
...
@@ -184,6 +198,9 @@ public class ModuleClassLoader extends URLClassLoader {
if
(
Modifier
.
isAbstract
(
cla
.
getModifiers
())){
return
false
;
}
if
(
isHandler
(
cla
))
{
return
true
;
}
if
(
cla
.
getAnnotation
(
Component
.
class
)!=
null
){
return
true
;
...
...
@@ -194,8 +211,15 @@ public class ModuleClassLoader extends URLClassLoader {
if
(
cla
.
getAnnotation
(
Service
.
class
)!=
null
){
return
true
;
}
if
(
cla
.
getAnnotation
(
Service
.
class
)!=
null
){
return
true
;
}
return
false
;
}
protected
boolean
isHandler
(
Class
<?>
beanType
)
{
return
AnnotatedElementUtils
.
hasAnnotation
(
beanType
,
Controller
.
class
)
||
AnnotatedElementUtils
.
hasAnnotation
(
beanType
,
RequestMapping
.
class
);
}
}
backend/src/main/java/io/dataease/plugins/server/PluginCommonServer.java
浏览文件 @
c03b82fd
...
...
@@ -2,6 +2,7 @@ package io.dataease.plugins.server;
import
io.dataease.commons.utils.ServletUtils
;
import
io.dataease.plugins.common.dto.PluginSysMenu
;
import
io.dataease.plugins.common.service.PluginComponentService
;
import
io.dataease.plugins.common.service.PluginMenuService
;
import
io.dataease.plugins.config.SpringContextUtil
;
import
org.springframework.web.bind.annotation.GetMapping
;
...
...
@@ -9,7 +10,6 @@ import org.springframework.web.bind.annotation.PathVariable;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
import
springfox.documentation.annotations.ApiIgnore
;
import
javax.servlet.http.HttpServletResponse
;
import
java.io.BufferedInputStream
;
import
java.io.IOException
;
...
...
@@ -25,7 +25,7 @@ import java.util.concurrent.atomic.AtomicReference;
public
class
PluginCommonServer
{
@GetMapping
(
"/async/{menuId}"
)
public
void
component
Info
(
@PathVariable
Long
menuId
)
{
public
void
menu
Info
(
@PathVariable
Long
menuId
)
{
Map
<
String
,
PluginMenuService
>
pluginMenuServiceMap
=
SpringContextUtil
.
getApplicationContext
().
getBeansOfType
(
PluginMenuService
.
class
);
pluginMenuServiceMap
.
values
().
stream
().
forEach
(
service
->
{
AtomicReference
<
PluginSysMenu
>
atomicReference
=
new
AtomicReference
<>();
...
...
@@ -65,4 +65,41 @@ public class PluginCommonServer {
return
;
});
}
@GetMapping
(
"/component/{componentName}"
)
public
void
componentInfo
(
@PathVariable
String
componentName
)
{
Map
<
String
,
PluginComponentService
>
beansOfType
=
SpringContextUtil
.
getApplicationContext
().
getBeansOfType
(
PluginComponentService
.
class
);
beansOfType
.
values
().
stream
().
forEach
(
service
->
{
List
<
String
>
components
=
service
.
components
();
if
(
components
.
contains
(
componentName
))
{
HttpServletResponse
response
=
ServletUtils
.
response
();
BufferedInputStream
bis
=
null
;
InputStream
inputStream
=
null
;
OutputStream
os
=
null
;
//输出流
try
{
inputStream
=
service
.
vueResource
(
componentName
);
byte
[]
buffer
=
new
byte
[
1024
];
os
=
response
.
getOutputStream
();
bis
=
new
BufferedInputStream
(
inputStream
);
int
i
=
bis
.
read
(
buffer
);
while
(
i
!=
-
1
){
os
.
write
(
buffer
,
0
,
i
);
i
=
bis
.
read
(
buffer
);
}
os
.
flush
();
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
finally
{
try
{
bis
.
close
();
inputStream
.
close
();
os
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
return
;
}
});
}
}
backend/src/main/java/io/dataease/plugins/server/SSOServer.java
0 → 100644
浏览文件 @
c03b82fd
package
io
.
dataease
.
plugins
.
server
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
import
javax.servlet.http.Cookie
;
import
javax.servlet.http.HttpServletResponse
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.servlet.ModelAndView
;
import
io.dataease.auth.entity.SysUserEntity
;
import
io.dataease.auth.entity.TokenInfo
;
import
io.dataease.auth.service.AuthUserService
;
import
io.dataease.auth.util.JWTUtils
;
import
io.dataease.commons.exception.DEException
;
import
io.dataease.commons.utils.CodingUtil
;
import
io.dataease.commons.utils.ServletUtils
;
import
io.dataease.plugins.config.SpringContextUtil
;
import
io.dataease.plugins.xpack.display.dto.response.SysSettingDto
;
import
io.dataease.plugins.xpack.oidc.dto.SSOToken
;
import
io.dataease.plugins.xpack.oidc.dto.SSOUserInfo
;
import
io.dataease.plugins.xpack.oidc.service.OidcXpackService
;
import
io.dataease.service.sys.SysUserService
;
@RequestMapping
(
"/sso"
)
@Controller
public
class
SSOServer
{
@Autowired
private
AuthUserService
authUserService
;
@Autowired
private
SysUserService
sysUserService
;
@GetMapping
(
"/callBack"
)
public
ModelAndView
callBack
(
@RequestParam
(
"code"
)
String
code
,
@RequestParam
(
"state"
)
String
state
)
{
Map
<
String
,
OidcXpackService
>
beansOfType
=
SpringContextUtil
.
getApplicationContext
().
getBeansOfType
((
OidcXpackService
.
class
));
if
(
beansOfType
.
keySet
().
size
()
==
0
)
{
DEException
.
throwException
(
"缺少oidc插件"
);
}
OidcXpackService
oidcXpackService
=
SpringContextUtil
.
getBean
(
OidcXpackService
.
class
);
Boolean
suuportOIDC
=
oidcXpackService
.
isSuuportOIDC
();
if
(!
suuportOIDC
)
{
DEException
.
throwException
(
"未开启oidc"
);
}
Map
<
String
,
String
>
config
=
config
(
oidcXpackService
);
SSOToken
ssoToken
=
oidcXpackService
.
requestSsoToken
(
config
,
code
,
state
);
SSOUserInfo
ssoUserInfo
=
oidcXpackService
.
requestUserInfo
(
config
,
ssoToken
.
getAccessToken
());
SysUserEntity
sysUserEntity
=
authUserService
.
getUserByName
(
ssoUserInfo
.
getUserName
());
if
(
null
==
sysUserEntity
){
sysUserService
.
saveOIDCUser
(
ssoUserInfo
);
sysUserEntity
=
authUserService
.
getUserByName
(
ssoUserInfo
.
getUserName
());
}
TokenInfo
tokenInfo
=
TokenInfo
.
builder
().
userId
(
sysUserEntity
.
getUserId
()).
username
(
sysUserEntity
.
getUsername
()).
build
();
String
realPwd
=
CodingUtil
.
md5
(
sysUserService
.
defaultPWD
());
String
token
=
JWTUtils
.
sign
(
tokenInfo
,
realPwd
);
ServletUtils
.
setToken
(
token
);
HttpServletResponse
response
=
ServletUtils
.
response
();
Cookie
cookie_token
=
new
Cookie
(
"Authorization"
,
token
);
cookie_token
.
setPath
(
"/"
);
Cookie
cookie_id_token
=
new
Cookie
(
"IdToken"
,
ssoToken
.
getIdToken
());
cookie_id_token
.
setPath
(
"/"
);
Cookie
cookie_ac_token
=
new
Cookie
(
"AccessToken"
,
ssoToken
.
getAccessToken
());
cookie_ac_token
.
setPath
(
"/"
);
response
.
addCookie
(
cookie_token
);
response
.
addCookie
(
cookie_id_token
);
response
.
addCookie
(
cookie_ac_token
);
ModelAndView
modelAndView
=
new
ModelAndView
(
"redirect:/"
);
return
modelAndView
;
}
private
Map
<
String
,
String
>
config
(
OidcXpackService
oidcXpackService
)
{
List
<
SysSettingDto
>
sysSettingDtos
=
oidcXpackService
.
oidcSettings
();
Map
<
String
,
String
>
config
=
sysSettingDtos
.
stream
().
collect
(
Collectors
.
toMap
(
SysSettingDto:
:
getParamKey
,
SysSettingDto:
:
getParamValue
));
return
config
;
}
}
backend/src/main/java/io/dataease/plugins/server/XOidcServer.java
浏览文件 @
c03b82fd
...
...
@@ -4,9 +4,11 @@ package io.dataease.plugins.server;
import
io.dataease.plugins.config.SpringContextUtil
;
import
io.dataease.plugins.xpack.display.dto.response.SysSettingDto
;
import
io.dataease.plugins.xpack.oidc.service.OidcXpackService
;
import
org.apache.commons.lang3.StringUtils
;
import
org.springframework.web.bind.annotation.*
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
@RequestMapping
(
"/plugin/oidc"
)
@RestController
...
...
@@ -24,4 +26,34 @@ public class XOidcServer {
OidcXpackService
oidcXpackService
=
SpringContextUtil
.
getBean
(
OidcXpackService
.
class
);
oidcXpackService
.
save
(
settings
);
}
@PostMapping
(
value
=
"/authInfo"
)
public
Map
<
String
,
Object
>
authInfo
()
{
OidcXpackService
oidcXpackService
=
SpringContextUtil
.
getBean
(
OidcXpackService
.
class
);
Map
<
String
,
Object
>
result
=
new
HashMap
<
String
,
Object
>();
List
<
SysSettingDto
>
oidcSettings
=
oidcXpackService
.
oidcSettings
();
Map
<
String
,
String
>
authParam
=
new
HashMap
<>();
authParam
.
put
(
"response_type"
,
"code"
);
authParam
.
put
(
"state"
,
"state"
);
// authParam.put("redirect_uri", "http://localhost:9528");
oidcSettings
.
forEach
(
param
->
{
if
(
StringUtils
.
isNotBlank
(
param
.
getParamKey
()))
{
if
(
StringUtils
.
equals
(
param
.
getParamKey
(),
"oidc.authEndpoint"
))
{
result
.
put
(
"authEndpoint"
,
param
.
getParamValue
());
}
if
(
StringUtils
.
equals
(
param
.
getParamKey
(),
"oidc.scope"
))
{
authParam
.
put
(
"scope"
,
param
.
getParamValue
());
}
if
(
StringUtils
.
equals
(
param
.
getParamKey
(),
"oidc.clientId"
))
{
authParam
.
put
(
"client_id"
,
param
.
getParamValue
());
}
}
});
result
.
put
(
"authParam"
,
authParam
);
return
result
;
}
}
backend/src/main/java/io/dataease/service/sys/SysUserService.java
浏览文件 @
c03b82fd
...
...
@@ -22,6 +22,8 @@ import io.dataease.controller.sys.response.SysUserGridResponse;
import
io.dataease.controller.sys.response.SysUserRole
;
import
io.dataease.i18n.Translator
;
import
io.dataease.plugins.common.entity.XpackLdapUserEntity
;
import
io.dataease.plugins.xpack.oidc.dto.SSOUserInfo
;
import
org.apache.commons.collections4.CollectionUtils
;
import
org.apache.commons.lang3.ObjectUtils
;
import
org.apache.commons.lang3.StringUtils
;
...
...
@@ -31,6 +33,8 @@ import org.springframework.stereotype.Service;
import
org.springframework.transaction.annotation.Transactional
;
import
javax.annotation.Resource
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.stream.Collectors
;
...
...
@@ -103,6 +107,33 @@ public class SysUserService {
return
insert
;
}
@Transactional
public
void
saveOIDCUser
(
SSOUserInfo
ssoUserInfo
)
{
long
now
=
System
.
currentTimeMillis
();
SysUser
sysUser
=
new
SysUser
();
sysUser
.
setUsername
(
ssoUserInfo
.
getUserName
());
sysUser
.
setNickName
(
ssoUserInfo
.
getNickName
());
sysUser
.
setEmail
(
ssoUserInfo
.
getEmail
());
sysUser
.
setPassword
(
CodingUtil
.
md5
(
DEFAULT_PWD
));
sysUser
.
setCreateTime
(
now
);
sysUser
.
setUpdateTime
(
now
);
sysUser
.
setEnabled
(
1L
);
sysUser
.
setLanguage
(
"zh_CN"
);
sysUser
.
setFrom
(
2
);
sysUserMapper
.
insert
(
sysUser
);
SysUser
dbUser
=
findOne
(
sysUser
);
if
(
null
!=
dbUser
&&
null
!=
dbUser
.
getUserId
())
{
// oidc默认角色是普通员工
List
<
Long
>
roleIds
=
new
ArrayList
<
Long
>();
roleIds
.
add
(
2L
);
saveUserRoles
(
dbUser
.
getUserId
(),
roleIds
);
}
}
public
String
defaultPWD
()
{
return
DEFAULT_PWD
;
}
@Transactional
public
void
saveLdapUsers
(
LdapAddRequest
request
)
{
long
now
=
System
.
currentTimeMillis
();
...
...
@@ -116,6 +147,7 @@ public class SysUserService {
sysUser
.
setCreateTime
(
now
);
sysUser
.
setUpdateTime
(
now
);
sysUser
.
setEnabled
(
request
.
getEnabled
());
sysUser
.
setLanguage
(
"zh_CN"
);
sysUser
.
setFrom
(
1
);
return
sysUser
;
}).
collect
(
Collectors
.
toList
());
...
...
frontend/src/api/user.js
浏览文件 @
c03b82fd
...
...
@@ -57,3 +57,10 @@ export function ldapStatus() {
method
:
'post'
})
}
export
function
oidcStatus
()
{
return
request
({
url
:
'/api/auth/isOpenOidc'
,
method
:
'post'
})
}
frontend/src/views/login/index.vue
浏览文件 @
c03b82fd
...
...
@@ -15,11 +15,11 @@
{{
$t
(
'login.welcome'
)
+
(
uiInfo
&&
uiInfo
[
'ui.title'
]
&&
uiInfo
[
'ui.title'
].
paramValue
||
' DataEase'
)
}}
</div>
<div
class=
"login-form"
>
<el-form-item
v-if=
"
openLdap
"
>
<el-radio-group
v-if=
"
openLdap"
v-model=
"loginForm.l
oginType"
>
<el-radio
v-if=
"openLdap"
:label=
"0"
size=
"mini"
>
普通登录
</el-radio>
<el-radio
v-if=
"
openLdap
"
:label=
"1"
size=
"mini"
>
LDAP
</el-radio>
<el-form-item
v-if=
"
loginTypes.length > 1
"
>
<el-radio-group
v-if=
"
loginTypes.length > 1"
v-model=
"loginForm.loginType"
@
change=
"changeL
oginType"
>
<el-radio
:label=
"0"
size=
"mini"
>
普通登录
</el-radio>
<el-radio
v-if=
"
loginTypes.includes(1)
"
:label=
"1"
size=
"mini"
>
LDAP
</el-radio>
<el-radio
v-if=
"loginTypes.includes(2)"
:label=
"2"
size=
"mini"
>
OIDC
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
prop=
"username"
>
...
...
@@ -56,41 +56,20 @@
</el-col>
</el-row>
</div>
<plugin-com
v-if=
"loginTypes.includes(2) && loginForm.loginType === 2"
ref=
"SSOComponent"
component-name=
"SSOComponent"
/>
</div>
</
template
>
<
script
>
import
{
encrypt
}
from
'@/utils/rsaEncrypt'
import
{
ldapStatus
}
from
'@/api/user'
import
{
ldapStatus
,
oidcStatus
}
from
'@/api/user'
import
{
getSysUI
}
from
'@/utils/auth'
import
PluginCom
from
'@/views/system/plugin/PluginCom'
export
default
{
name
:
'Login'
,
components
:
{
PluginCom
},
data
()
{
// const validateUsername = (rule, value, callback) => {
// const userName = value.trim()
// validateUserName({ userName: userName }).then(res => {
// if (res.data) {
// callback()
// } else {
// callback(this.$t('login.username_error'))
// }
// }).catch(() => {
// callback(this.$t('login.username_error'))
// })
// // if (!validUsername(value)) {
// // callback(new Error('Please enter the correct user name'))
// // } else {
// // callback()
// // }
// }
// const validatePassword = (rule, value, callback) => {
// if (value.length
<
8
)
{
// callback(this.$t('login.password_error'))
// } else {
// callback()
// }
// }
return
{
loginForm
:
{
loginType
:
0
,
...
...
@@ -108,7 +87,7 @@ export default {
loginImageUrl
:
null
,
loginLogoUrl
:
null
,
axiosFinished
:
false
,
openLdap
:
false
loginTypes
:
[
0
]
}
},
computed
:
{
...
...
@@ -126,7 +105,15 @@ export default {
},
beforeCreate
()
{
ldapStatus
().
then
(
res
=>
{
this
.
openLdap
=
res
.
success
&&
res
.
data
if
(
res
.
success
&&
res
.
data
)
{
this
.
loginTypes
.
push
(
1
)
}
})
oidcStatus
().
then
(
res
=>
{
if
(
res
.
success
&&
res
.
data
)
{
this
.
loginTypes
.
push
(
2
)
}
})
},
created
()
{
...
...
@@ -169,6 +156,12 @@ export default {
return
false
}
})
},
changeLoginType
(
val
)
{
if
(
val
!==
2
)
return
this
.
$nextTick
(()
=>
{
})
}
}
}
...
...
frontend/src/views/system/plugin/PluginCom.vue
0 → 100644
浏览文件 @
c03b82fd
<
template
>
<div>
<async-component
v-if=
"showAsync"
:url=
"url"
@
execute-axios=
"executeAxios"
@
on-add-languanges=
"addLanguages"
@
plugin-call-back=
"pluginCallBack"
/>
<div
v-else
>
<h1>
未知组件无法展示
</h1>
</div>
</div>
</
template
>
<
script
>
import
AsyncComponent
from
'@/components/AsyncComponent'
import
i18n
from
'@/lang'
import
bus
from
'@/utils/bus'
import
{
execute
}
from
'@/api/system/dynamic'
export
default
{
name
:
'PluginCom'
,
components
:
{
AsyncComponent
},
props
:
{
componentName
:
{
type
:
String
,
default
:
null
}
},
data
()
{
return
{
showAsync
:
false
,
baseUrl
:
'/api/pluginCommon/component/'
,
url
:
null
}
},
created
()
{
if
(
this
.
componentName
)
{
this
.
showAsync
=
true
this
.
url
=
this
.
baseUrl
+
this
.
componentName
}
else
{
this
.
showAsync
=
false
}
},
methods
:
{
// hasLicense
executeAxios
(
options
)
{
execute
(
options
).
then
(
res
=>
{
if
(
options
.
callBack
)
{
options
.
callBack
(
res
)
}
}).
catch
(
e
=>
{
if
(
options
.
callBack
)
{
options
.
callBack
(
e
)
}
})
},
addLanguages
(
options
)
{
for
(
const
key
in
i18n
.
messages
)
{
if
(
Object
.
hasOwnProperty
.
call
(
i18n
.
messages
,
key
))
{
const
element
=
options
[
key
]
i18n
.
mergeLocaleMessage
(
key
,
element
)
}
}
},
pluginCallBack
(
param
)
{
const
{
eventName
,
eventParam
}
=
param
bus
.
$emit
(
eventName
,
eventParam
)
}
}
}
</
script
>
frontend/src/views/system/user/index.vue
浏览文件 @
c03b82fd
...
...
@@ -22,7 +22,7 @@
<!-- <el-table-column prop="gender" :label="$t('commons.gender')" width="60" /> -->
<el-table-column
prop=
"from"
:label=
"$t('user.source')"
width=
"80"
>
<
template
slot-scope=
"scope"
>
<div>
{{
scope
.
row
.
from
===
0
?
'LOCAL'
:
'LDAP
'
}}
</div>
<div>
{{
scope
.
row
.
from
===
0
?
'LOCAL'
:
scope
.
row
.
from
===
1
?
'LDAP'
:
'OIDC
'
}}
</div>
</
template
>
</el-table-column>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论