Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
提交反馈
为 GitLab 提交贡献
登录
切换导航
I
ibizlab-boot-starters
项目
项目
详情
动态
版本
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
ibiz4jteam
ibizlab-boot-starters
提交
4546f370
提交
4546f370
编写于
9月 20, 2022
作者:
sq3536
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
提交uaa相关
上级
3b79c3b6
变更
11
隐藏空白字符变更
内嵌
并排
正在显示
11 个修改的文件
包含
97 行增加
和
144 行删除
+97
-144
BeanCache.java
...-data/src/main/java/cn/ibizlab/util/helper/BeanCache.java
+18
-0
CloudUserService.java
...c/main/java/cn/ibizlab/util/service/CloudUserService.java
+34
-14
IBZConfigService.java
...c/main/java/cn/ibizlab/util/service/IBZConfigService.java
+13
-0
IBZUSERServiceImpl.java
...main/java/cn/ibizlab/util/service/IBZUSERServiceImpl.java
+2
-2
CloudTokenUtil.java
...rc/main/java/cn/ibizlab/util/security/CloudTokenUtil.java
+0
-115
UAADEAuthority.java
...rc/main/java/cn/ibizlab/util/security/UAADEAuthority.java
+23
-5
UAAMenuAuthority.java
.../main/java/cn/ibizlab/util/security/UAAMenuAuthority.java
+2
-2
UAARoleAuthority.java
.../main/java/cn/ibizlab/util/security/UAARoleAuthority.java
+2
-2
UAAUniResAuthority.java
...ain/java/cn/ibizlab/util/security/UAAUniResAuthority.java
+1
-1
SimpleUserService.java
.../main/java/cn/ibizlab/util/service/SimpleUserService.java
+2
-2
ibzrt_rsa.pub
...boot-starter/src/main/resources/uaa/keypair/ibzrt_rsa.pub
+0
-1
未找到文件。
ibizlab-boot-starter-data/src/main/java/cn/ibizlab/util/helper/BeanCache.java
浏览文件 @
4546f370
...
...
@@ -28,6 +28,8 @@ public class BeanCache {
private
static
Map
<
String
,
BeanSchema
>
cache
=
new
HashMap
<>();
private
static
Object
objLock1
=
new
Object
();
private
static
BeanSchema
EMPTY
=
new
BeanSchema
();
@Getter
@Setter
@NoArgsConstructor
...
...
@@ -253,11 +255,27 @@ public class BeanCache {
}
public
static
<
T
>
BeanSchema
register
(
Class
<
T
>
clazz
)
{
return
BeanSchema
.
from
(
clazz
);
}
public
static
<
T
>
BeanSchema
get
(
Class
<
T
>
clazz
)
{
return
BeanSchema
.
from
(
clazz
);
}
public
static
<
T
>
BeanSchema
get
(
String
tag
)
{
if
(
cache
.
containsKey
(
tag
))
{
return
cache
.
get
(
tag
);
}
synchronized
(
objLock1
)
{
if
(
cache
.
containsKey
(
tag
))
{
return
cache
.
get
(
tag
);
}
}
return
EMPTY
;
}
public
static
<
T
>
boolean
hasAudit
(
Class
<
T
>
clazz
)
{
return
!
ObjectUtils
.
isEmpty
(
BeanCache
.
get
(
clazz
).
getAudits
());
}
...
...
ibizlab-boot-starter/src/main/java/cn/ibizlab/util/service/CloudUserService.java
→
ibizlab-boot-starter
-data
/src/main/java/cn/ibizlab/util/service/CloudUserService.java
浏览文件 @
4546f370
package
cn
.
ibizlab
.
util
.
service
;
import
cn.ibizlab.util.cache.redis.CustomJacksonSerializer
;
import
cn.ibizlab.util.client.IBZUAAFeignClient
;
import
cn.ibizlab.util.errors.BadRequestAlertException
;
import
cn.ibizlab.util.errors.UnauthorizedException
;
import
cn.ibizlab.util.helper.BeanCache
;
import
cn.ibizlab.util.security.*
;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson.util.TypeUtils
;
import
com.fasterxml.jackson.core.type.TypeReference
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
lombok.extern.slf4j.Slf4j
;
...
...
@@ -17,8 +16,6 @@ import org.springframework.cache.annotation.CacheEvict;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.context.annotation.Lazy
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.security.core.GrantedAuthority
;
import
org.springframework.stereotype.Service
;
import
org.springframework.util.DigestUtils
;
import
org.springframework.util.ObjectUtils
;
...
...
@@ -30,8 +27,6 @@ import javax.servlet.http.HttpServletRequest;
import
java.io.IOException
;
import
java.net.URLDecoder
;
import
java.nio.charset.StandardCharsets
;
import
java.text.DateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
@Slf4j
...
...
@@ -48,7 +43,7 @@ public class CloudUserService extends IBZUAAUserService {
boolean
enablePermissionValid
;
//是否开启权限校验
@Value
(
"${ibiz.systemid}"
)
p
rivate
String
systemId
;
p
ublic
String
systemId
;
@Override
public
boolean
isEnablePermissionValid
()
{
...
...
@@ -68,7 +63,7 @@ public class CloudUserService extends IBZUAAUserService {
private
TypeReference
<
Collection
<
UAAGrantedAuthority
>>
UAAGrantedAuthorityListType
=
new
TypeReference
<
Collection
<
UAAGrantedAuthority
>>(){};
@Override
@Cacheable
(
value
=
"ibzuaa_users"
,
key
=
"
'getByUsername
:'+#p0"
)
@Cacheable
(
value
=
"ibzuaa_users"
,
key
=
"
#root.target.systemId+'
:'+#p0"
)
public
AuthenticationUser
loadUserByUsername
(
String
username
)
{
Object
obj
=
redisTemplate
.
opsForValue
().
get
(
"ibiz-cloud-uaa-user-"
+
username
);
if
(
obj
==
null
)
{
...
...
@@ -98,7 +93,7 @@ public class CloudUserService extends IBZUAAUserService {
srforgid
=
null
;
}
Collection
<
?
extends
GrantedAuthority
>
authorities
=
null
;
Collection
<
UAA
GrantedAuthority
>
authorities
=
null
;
if
(
StringUtils
.
hasLength
(
srfsystemid
)
&&
StringUtils
.
hasLength
(
srfdcid
)
&&
StringUtils
.
hasLength
(
srfdcsystemid
)
&&
StringUtils
.
hasLength
(
srfuserid
))
{
...
...
@@ -156,6 +151,7 @@ public class CloudUserService extends IBZUAAUserService {
throw
new
UnauthorizedException
(
String
.
format
(
"用户[%1$s][%2$s]使用API模式访问系统"
,
dcEmployee
.
getUserid
(),
dcEmployee
.
getUsername
()));
}
}
else
if
(
StringUtils
.
hasLength
(
srfsystemid
)
&&
StringUtils
.
hasLength
(
srforgid
))
{
uaaFeignClient
.
getAppData
();
AuthenticationUser
employee
=
this
.
getEmployee
(
srfsystemid
,
srforgid
,
dcEmployee
.
getUsername
(),
authToken
);
if
(
employee
!=
null
)
{
if
(
dcEmployee
.
getSuperuser
()
==
1
)
...
...
@@ -169,6 +165,11 @@ public class CloudUserService extends IBZUAAUserService {
if
(
StringUtils
.
hasLength
(
strDCSystemId
))
{
authorities
=
this
.
getGrantedAuthorities
(
strDCSystemId
,
dcEmployee
.
getUsername
(),
authToken
);
if
(!
ObjectUtils
.
isEmpty
(
authorities
))
{
if
(
dcEmployee
.
getSuperuser
()
==
1
){
UAARoleAuthority
admin
=
new
UAARoleAuthority
();
admin
.
setRoleTag
(
"SUPERADMIN"
);
authorities
.
add
(
admin
);
}
dcEmployee
.
setAuthorities
((
Collection
)
authorities
);
JSONObject
permission
=
new
JSONObject
();
permission
.
put
(
"authorities"
,
authorities
);
...
...
@@ -187,14 +188,33 @@ public class CloudUserService extends IBZUAAUserService {
}
protected
Collection
<
UAAGrantedAuthority
>
getGrantedAuthorities
(
String
strDCSystemId
,
String
strUAAUserName
,
String
strToken
){
String
strCacheCat
=
String
.
format
(
"ibiz-cloud-uaa-cat-%
2$s--%3
$s"
,
strUAAUserName
,
DigestUtils
.
md5DigestAsHex
(
strToken
.
getBytes
(
StandardCharsets
.
UTF_8
)));;
String
strCacheCat
=
String
.
format
(
"ibiz-cloud-uaa-cat-%
1$s--%2
$s"
,
strUAAUserName
,
DigestUtils
.
md5DigestAsHex
(
strToken
.
getBytes
(
StandardCharsets
.
UTF_8
)));;
String
strCacheTag
=
String
.
format
(
"authorities-%1$s"
,
strDCSystemId
);
Object
obj
=
this
.
redisTemplate
.
opsForHash
().
get
(
strCacheCat
,
strCacheTag
);
if
(!
ObjectUtils
.
isEmpty
(
obj
))
{
try
{
return
objectMapper
.
readValue
(
objectMapper
.
writeValueAsString
(
obj
),
this
.
UAAGrantedAuthorityListType
);
Map
<
String
,
UAAGrantedAuthority
>
rt
=
new
LinkedHashMap
<>();
Collection
<
UAAGrantedAuthority
>
tmp
=
objectMapper
.
readValue
(
objectMapper
.
writeValueAsString
(
obj
),
this
.
UAAGrantedAuthorityListType
);
if
(!
ObjectUtils
.
isEmpty
(
tmp
))
{
tmp
.
forEach
(
item
->{
if
(
item
instanceof
UAADEAuthority
)
{
UAADEAuthority
deAuth
=(
UAADEAuthority
)
item
;
deAuth
.
setEntityCode
(
BeanCache
.
get
(
deAuth
.
getEntity
()).
getCodeName
());
if
(
ObjectUtils
.
isEmpty
(
deAuth
.
getEntityCode
()))
return
;
}
else
{
rt
.
put
(
item
.
getAuthority
(),
item
);
}
});
return
rt
.
values
();
}
}
catch
(
IOException
e
)
{
}
...
...
@@ -203,7 +223,7 @@ public class CloudUserService extends IBZUAAUserService {
}
protected
AuthenticationUser
getEmployee
(
String
strSystemId
,
String
strOrgId
,
String
strUAAUserName
,
String
strToken
)
{
String
strCacheCat
=
String
.
format
(
"ibiz-cloud-uaa-cat-%
2$s--%3
$s"
,
strUAAUserName
,
DigestUtils
.
md5DigestAsHex
(
strToken
.
getBytes
(
StandardCharsets
.
UTF_8
)));;
String
strCacheCat
=
String
.
format
(
"ibiz-cloud-uaa-cat-%
1$s--%2
$s"
,
strUAAUserName
,
DigestUtils
.
md5DigestAsHex
(
strToken
.
getBytes
(
StandardCharsets
.
UTF_8
)));;
String
strCacheTag
=
String
.
format
(
"sysemp-%1$s--%2$s"
,
strSystemId
,
strOrgId
);
Object
obj
=
this
.
redisTemplate
.
opsForHash
().
get
(
strCacheCat
,
strCacheTag
);
if
(!
ObjectUtils
.
isEmpty
(
obj
))
{
...
...
@@ -226,7 +246,7 @@ public class CloudUserService extends IBZUAAUserService {
}
@Override
@CacheEvict
(
value
=
"ibzuaa_users"
,
key
=
"
'getByUsername
:'+#p0"
)
@CacheEvict
(
value
=
"ibzuaa_users"
,
key
=
"
#root.target.systemId+'
:'+#p0"
)
public
void
resetByUsername
(
String
username
)
{
}
}
ibizlab-boot-starter-data/src/main/java/cn/ibizlab/util/service/IBZConfigService.java
浏览文件 @
4546f370
package
cn
.
ibizlab
.
util
.
service
;
import
cn.ibizlab.util.domain.EntityBase
;
import
cn.ibizlab.util.domain.IBZConfig
;
import
cn.ibizlab.util.errors.BadRequestAlertException
;
import
cn.ibizlab.util.helper.BeanCache
;
import
cn.ibizlab.util.helper.DataObject
;
import
cn.ibizlab.util.mapper.IBZConfigMapper
;
import
com.alibaba.fastjson.JSON
;
...
...
@@ -17,10 +19,21 @@ import org.springframework.stereotype.Service;
import
org.springframework.util.ObjectUtils
;
import
org.springframework.util.StringUtils
;
import
javax.annotation.PostConstruct
;
import
java.util.ServiceLoader
;
@Slf4j
@Service
public
class
IBZConfigService
extends
ServiceImpl
<
IBZConfigMapper
,
IBZConfig
>
implements
IService
<
IBZConfig
>
{
@PostConstruct
public
void
init
()
{
ServiceLoader
<
EntityBase
>
loader
=
ServiceLoader
.
load
(
EntityBase
.
class
);
for
(
EntityBase
entityBase
:
loader
){
BeanCache
.
register
(
entityBase
.
getClass
());
}
}
@Value
(
"${ibiz.systemid:ibznotify}"
)
private
String
systemId
;
...
...
ibizlab-boot-starter-data/src/main/java/cn/ibizlab/util/service/IBZUSERServiceImpl.java
浏览文件 @
4546f370
...
...
@@ -49,7 +49,7 @@ public class IBZUSERServiceImpl extends ServiceImpl<IBZUSERMapper, IBZUSER> impl
@Override
@Cacheable
(
value
=
"
sys_users"
,
key
=
"'getByUsername
:'+#p0"
)
@Cacheable
(
value
=
"
ibzuaa_users"
,
key
=
"#root.target.systemId+'
:'+#p0"
)
public
AuthenticationUser
loadUserByUsername
(
String
username
)
{
if
(
StringUtils
.
isEmpty
(
username
))
{
throw
new
UsernameNotFoundException
(
"用户名为空"
);
...
...
@@ -103,7 +103,7 @@ public class IBZUSERServiceImpl extends ServiceImpl<IBZUSERMapper, IBZUSER> impl
}
@CacheEvict
(
value
=
"sys_users"
,
key
=
"
'getByUsername
:'+#p0"
)
@CacheEvict
(
value
=
"sys_users"
,
key
=
"
#root.target.systemId+'
:'+#p0"
)
public
void
resetByUsername
(
String
username
)
{
}
...
...
ibizlab-boot-starter/src/main/java/cn/ibizlab/util/security/CloudTokenUtil.java
已删除
100644 → 0
浏览文件 @
3b79c3b6
package
cn
.
ibizlab
.
util
.
security
;
import
io.jsonwebtoken.Claims
;
import
io.jsonwebtoken.Clock
;
import
io.jsonwebtoken.Jwts
;
import
io.jsonwebtoken.impl.DefaultClock
;
import
lombok.SneakyThrows
;
import
org.apache.commons.codec.binary.Base64
;
import
org.apache.commons.io.IOUtils
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
;
import
org.springframework.security.core.userdetails.UserDetails
;
import
org.springframework.stereotype.Component
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.Serializable
;
import
java.nio.charset.Charset
;
import
java.security.KeyFactory
;
import
java.security.NoSuchAlgorithmException
;
import
java.security.PublicKey
;
import
java.security.spec.InvalidKeySpecException
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.util.Date
;
import
java.util.function.Function
;
@Component
@ConditionalOnExpression
(
"'${ibiz.auth.token.util:UAATokenUtil}'.equals('CloudTokenUtil')"
)
public
class
CloudTokenUtil
implements
AuthTokenUtil
,
Serializable
{
private
static
final
long
serialVersionUID
=
-
3301605591108950415L
;
private
Clock
clock
=
DefaultClock
.
INSTANCE
;
@Value
(
"${ibiz.jwt.secret:ibzsecret}"
)
private
String
secret
;
@Value
(
"${ibiz.jwt.expiration:7200000}"
)
private
Long
expiration
;
@Value
(
"${ibiz.jwt.header:Authorization}"
)
private
String
tokenHeader
;
public
String
getUsernameFromToken
(
String
token
)
{
return
getClaimFromToken
(
token
,
Claims:
:
getSubject
);
}
public
Date
getIssuedAtDateFromToken
(
String
token
)
{
return
getClaimFromToken
(
token
,
Claims:
:
getIssuedAt
);
}
public
Date
getExpirationDateFromToken
(
String
token
)
{
return
getClaimFromToken
(
token
,
Claims:
:
getExpiration
);
}
public
<
T
>
T
getClaimFromToken
(
String
token
,
Function
<
Claims
,
T
>
claimsResolver
)
{
final
Claims
claims
=
getAllClaimsFromToken
(
token
);
return
claimsResolver
.
apply
(
claims
);
}
public
Claims
getAllClaimsFromToken
(
String
token
)
{
PublicKey
publicKey
=
getPublicKey
(
getPublicKeyString
());
return
Jwts
.
parser
()
.
setSigningKey
(
publicKey
)
.
parseClaimsJws
(
token
)
.
getBody
();
}
public
String
generateToken
(
UserDetails
userDetails
)
{
return
null
;
}
public
Boolean
validateToken
(
String
token
,
UserDetails
userDetails
)
{
AuthenticationUser
user
=
(
AuthenticationUser
)
userDetails
;
user
.
setToken
(
token
);
final
Date
created
=
getIssuedAtDateFromToken
(
token
);
final
Date
expiration
=
getExpirationDateFromToken
(
token
);
user
.
setExpiration
(
expiration
);
return
!
expiration
.
before
(
clock
.
now
());
}
@SneakyThrows
protected
String
getPublicKeyString
()
{
String
key
=
""
;
String
usrHome
=
System
.
getProperty
(
"user.home"
)
+
"/.ibzrt"
;
File
pubKeyFile
=
new
File
(
usrHome
,
"ibzrt_rsa.pub"
);
if
(!
pubKeyFile
.
exists
())
{
key
=
IOUtils
.
toString
(
this
.
getClass
().
getResourceAsStream
(
"/uaa/keypair/ibzrt_rsa.pub"
));
}
else
{
key
=
IOUtils
.
toString
(
new
FileInputStream
(
pubKeyFile
));
}
return
key
;
}
/**
* 获取PublicKey对象
* @param publicKeyBase64
* @return
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
@SneakyThrows
public
PublicKey
getPublicKey
(
String
publicKeyBase64
)
{
byte
[]
byteKey
=
Base64
.
decodeBase64
(
publicKeyBase64
);
X509EncodedKeySpec
x509EncodedKeySpec
=
new
X509EncodedKeySpec
(
byteKey
);
KeyFactory
keyFactory
=
KeyFactory
.
getInstance
(
"RSA"
);
return
keyFactory
.
generatePublic
(
x509EncodedKeySpec
);
}
}
ibizlab-boot-starter/src/main/java/cn/ibizlab/util/security/UAADEAuthority.java
浏览文件 @
4546f370
package
cn
.
ibizlab
.
util
.
security
;
import
lombok.Data
;
import
org.springframework.util.ObjectUtils
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.*
;
@Data
public
class
UAADEAuthority
extends
UAAGrantedAuthority
{
private
String
entity
;
private
String
entityCode
;
private
Integer
enableorgdr
;
private
Integer
enabledeptdr
;
private
Integer
enabledeptbc
;
private
Long
orgdr
;
private
Long
deptdr
;
private
Integer
orgdr
;
private
Integer
deptdr
;
private
String
deptbc
;
private
String
systemid
;
private
Integer
isAllData
;
private
boolean
dataset
;
private
String
bscope
;
private
String
authority
;
private
List
<
Map
<
String
,
String
>>
deAction
=
new
ArrayList
<>();
public
UAADEAuthority
(){
this
.
setType
(
"OPPRIV"
);
}
@Override
public
String
getAuthority
()
{
return
this
.
getName
();
...
...
@@ -33,5 +37,19 @@ public class UAADEAuthority extends UAAGrantedAuthority {
public
void
setAuthority
(
String
name
)
{
}
public
Set
<
String
>
getAuthorities
()
{
Set
<
String
>
sets
=
new
LinkedHashSet
<>();
if
(
ObjectUtils
.
isEmpty
(
entityCode
))
return
sets
;
if
(
ObjectUtils
.
isEmpty
(
systemid
))
return
sets
;
deAction
.
forEach
(
item
->{
String
scope
=
""
;
// if(item.containsKey("READ"))
});
return
sets
;
}
}
ibizlab-boot-starter/src/main/java/cn/ibizlab/util/security/UAAMenuAuthority.java
浏览文件 @
4546f370
...
...
@@ -13,12 +13,12 @@ public class UAAMenuAuthority extends UAAGrantedAuthority {
@Override
public
String
getAuthority
()
{
return
menuTag
;
return
"APPMENU_"
+
menuTag
;
}
public
void
setAuthority
(
String
menuTag
)
{
this
.
menuTag
=
menuTag
;
}
}
ibizlab-boot-starter/src/main/java/cn/ibizlab/util/security/UAARoleAuthority.java
浏览文件 @
4546f370
...
...
@@ -13,12 +13,12 @@ public class UAARoleAuthority extends UAAGrantedAuthority {
@Override
public
String
getAuthority
()
{
return
roleTag
;
return
"ROLE_"
+
roleTag
;
}
public
void
setAuthority
(
String
roleTag
)
{
this
.
roleTag
=
roleTag
;
}
}
ibizlab-boot-starter/src/main/java/cn/ibizlab/util/security/UAAUniResAuthority.java
浏览文件 @
4546f370
...
...
@@ -13,7 +13,7 @@ public class UAAUniResAuthority extends UAAGrantedAuthority {
@Override
public
String
getAuthority
()
{
return
unionResTag
;
return
"UNIRES_"
+
unionResTag
;
}
public
void
setAuthority
(
String
unionResTag
)
{
...
...
ibizlab-boot-starter/src/main/java/cn/ibizlab/util/service/SimpleUserService.java
浏览文件 @
4546f370
...
...
@@ -38,7 +38,7 @@ public class SimpleUserService implements AuthenticationUserService {
return
systemId
;
}
@Override
@Cacheable
(
value
=
"
simple_users"
,
key
=
"'getByUsername
:'+#p0"
)
@Cacheable
(
value
=
"
ibzuaa_users"
,
key
=
"#root.target.systemId+'
:'+#p0"
)
public
AuthenticationUser
loadUserByUsername
(
String
username
)
{
AuthenticationUser
user
=
new
AuthenticationUser
();
String
[]
data
=
username
.
split
(
"[|]"
);
...
...
@@ -82,7 +82,7 @@ public class SimpleUserService implements AuthenticationUserService {
@Override
@CacheEvict
(
value
=
"simple_users"
,
key
=
"
'getByUsername
:'+#p0"
)
@CacheEvict
(
value
=
"simple_users"
,
key
=
"
#root.target.systemId+'
:'+#p0"
)
public
void
resetByUsername
(
String
username
)
{
}
...
...
ibizlab-boot-starter/src/main/resources/uaa/keypair/ibzrt_rsa.pub
已删除
100644 → 0
浏览文件 @
3b79c3b6
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCmk8+KYDkf6dEY5XMzNHRK3+GVDc4hPxyXHygyz7u+xrNhCXQytLhnzyNxl/3kcF/S/W02Sbc/bF9n5Eakbd4Fp7DMqU9j/3Dv9hoLUQjx0RQ+wSPg399orBCWejOJA/bcii8PGPSrj9AttGTDA3gq624zGoDDK8EzjOP+HhY81QIDAQAB
\ No newline at end of file
编辑
预览
Markdown
格式
0%
请重试
or
添加新附件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
先完成此消息的编辑!
取消
想要评论请
注册
或
登录