Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
D
dataease
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
njgzx
dataease
Commits
5f20b3fc
提交
5f20b3fc
authored
9月 14, 2021
作者:
fit2cloud-chenyw
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: sso单点登录
上级
ae48fbee
显示空白字符变更
内嵌
并排
正在显示
10 个修改的文件
包含
193 行增加
和
23 行删除
+193
-23
TokenInfo.java
backend/src/main/java/io/dataease/auth/entity/TokenInfo.java
+1
-1
AuthServer.java
...end/src/main/java/io/dataease/auth/server/AuthServer.java
+5
-5
ShiroServiceImpl.java
.../java/io/dataease/auth/service/impl/ShiroServiceImpl.java
+5
-0
JWTUtils.java
backend/src/main/java/io/dataease/auth/util/JWTUtils.java
+13
-7
PluginCommonServer.java
...n/java/io/dataease/plugins/server/PluginCommonServer.java
+39
-2
SSOServer.java
...d/src/main/java/io/dataease/plugins/server/SSOServer.java
+21
-6
XOidcServer.java
...src/main/java/io/dataease/plugins/server/XOidcServer.java
+33
-1
index.vue
frontend/src/views/login/index.vue
+6
-0
PluginCom.vue
frontend/src/views/system/plugin/PluginCom.vue
+69
-0
index.vue
frontend/src/views/system/user/index.vue
+1
-1
没有找到文件。
backend/src/main/java/io/dataease/auth/entity/TokenInfo.java
浏览文件 @
5f20b3fc
...
...
@@ -13,7 +13,7 @@ public class TokenInfo implements Serializable {
private
Long
userId
;
private
String
idToken
;
/* private String idToken; */
public
String
format
(){
return
username
+
","
+
userId
;
...
...
backend/src/main/java/io/dataease/auth/server/AuthServer.java
浏览文件 @
5f20b3fc
...
...
@@ -22,18 +22,18 @@ 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
{
...
...
@@ -115,13 +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
);
TokenInfo
tokenInfo
=
JWTUtils
.
tokenInfoByToken
(
token
);
String
idToken
=
tokenInfo
.
getIdToken
();
oidcXpackService
.
logout
(
idToken
);
}
// String token = ServletUtils.getToken();
if
(
StringUtils
.
isEmpty
(
token
)
||
StringUtils
.
equals
(
"null"
,
token
)
||
StringUtils
.
equals
(
"undefined"
,
token
))
{
return
"success"
;
}
...
...
backend/src/main/java/io/dataease/auth/service/impl/ShiroServiceImpl.java
浏览文件 @
5f20b3fc
...
...
@@ -60,6 +60,11 @@ public class ShiroServiceImpl implements ShiroService {
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
浏览文件 @
5f20b3fc
...
...
@@ -8,6 +8,7 @@ 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
;
...
...
@@ -38,9 +39,9 @@ public class JWTUtils {
Verification
verification
=
JWT
.
require
(
algorithm
)
.
withClaim
(
"username"
,
tokenInfo
.
getUsername
())
.
withClaim
(
"userId"
,
tokenInfo
.
getUserId
());
if
(
StringUtils
.
isNotBlank
(
tokenInfo
.
getIdToken
()))
{
/*
if (StringUtils.isNotBlank(tokenInfo.getIdToken())) {
verification.withClaim("idToken", tokenInfo.getIdToken());
}
}
*/
JWTVerifier
verifier
=
verification
.
build
();
verifier
.
verify
(
token
);
return
true
;
...
...
@@ -54,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
;
}
...
...
@@ -114,11 +120,11 @@ public class JWTUtils {
Builder
builder
=
JWT
.
create
()
.
withClaim
(
"username"
,
tokenInfo
.
getUsername
())
.
withClaim
(
"userId"
,
tokenInfo
.
getUserId
());
if
(
StringUtils
.
isNotBlank
(
tokenInfo
.
getIdToken
()))
{
/*
if (StringUtils.isNotBlank(tokenInfo.getIdToken())) {
builder.withClaim("idToken", tokenInfo.getIdToken());
}
return
builder
.
withExpiresAt
(
date
)
.
sign
(
algorithm
);
}
*/
return
builder
.
withExpiresAt
(
date
)
.
sign
(
algorithm
);
}
catch
(
Exception
e
)
{
return
null
;
}
...
...
backend/src/main/java/io/dataease/plugins/server/PluginCommonServer.java
浏览文件 @
5f20b3fc
...
...
@@ -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
浏览文件 @
5f20b3fc
...
...
@@ -3,6 +3,10 @@ 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
;
...
...
@@ -14,6 +18,7 @@ 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
;
...
...
@@ -33,8 +38,7 @@ public class SSOServer {
private
SysUserService
sysUserService
;
@GetMapping
(
"/callBack"
)
public
ModelAndView
callBack
(
@RequestParam
(
"code"
)
String
code
,
@RequestParam
(
"statue"
)
String
state
)
{
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插件"
);
...
...
@@ -44,18 +48,29 @@ public class SSOServer {
if
(!
suuportOIDC
)
{
DEException
.
throwException
(
"未开启oidc"
);
}
SSOToken
ssoToken
=
oidcXpackService
.
requestSsoToken
(
code
,
state
);
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
()).
idToken
(
ssoToken
.
getIdToken
()).
build
();
String
token
=
JWTUtils
.
sign
(
tokenInfo
,
sysUserService
.
defaultPWD
());
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
);
ModelAndView
modelAndView
=
new
ModelAndView
(
"/"
);
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
)
{
...
...
backend/src/main/java/io/dataease/plugins/server/XOidcServer.java
浏览文件 @
5f20b3fc
...
...
@@ -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
;
}
}
frontend/src/views/login/index.vue
浏览文件 @
5f20b3fc
...
...
@@ -56,6 +56,7 @@
</el-col>
</el-row>
</div>
<plugin-com
v-if=
"loginTypes.includes(2) && loginForm.loginType === 2"
ref=
"SSOComponent"
component-name=
"SSOComponent"
/>
</div>
</
template
>
...
...
@@ -64,8 +65,10 @@
import
{
encrypt
}
from
'@/utils/rsaEncrypt'
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
()
{
return
{
loginForm
:
{
...
...
@@ -156,6 +159,9 @@ export default {
},
changeLoginType
(
val
)
{
if
(
val
!==
2
)
return
this
.
$nextTick
(()
=>
{
})
}
}
}
...
...
frontend/src/views/system/plugin/PluginCom.vue
0 → 100644
浏览文件 @
5f20b3fc
<
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
浏览文件 @
5f20b3fc
...
...
@@ -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
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论