Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
zhangjian1949
microservices-platform
提交
6d3f8a75
microservices-platform
项目概览
zhangjian1949
/
microservices-platform
与 Fork 源项目一致
Fork自
zlt2000 / microservices-platform
通知
6
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
microservices-platform
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
6d3f8a75
编写于
5月 22, 2021
作者:
zlt2000
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
增加oidc协议单点登录样例工程oidc-sso
上级
6d50fc99
变更
13
展开全部
隐藏空白更改
内联
并排
Showing
13 changed file
with
444 addition
and
3 deletion
+444
-3
zlt-demo/sso-demo/README.md
zlt-demo/sso-demo/README.md
+1
-1
zlt-demo/sso-demo/oidc-sso/README.md
zlt-demo/sso-demo/oidc-sso/README.md
+25
-0
zlt-demo/sso-demo/oidc-sso/pom.xml
zlt-demo/sso-demo/oidc-sso/pom.xml
+50
-0
zlt-demo/sso-demo/oidc-sso/src/main/java/com/sso/demo/OidcSSOApplication.java
...dc-sso/src/main/java/com/sso/demo/OidcSSOApplication.java
+18
-0
zlt-demo/sso-demo/oidc-sso/src/main/java/com/sso/demo/controller/ApiController.java
.../src/main/java/com/sso/demo/controller/ApiController.java
+207
-0
zlt-demo/sso-demo/oidc-sso/src/main/resources/bootstrap.yml
zlt-demo/sso-demo/oidc-sso/src/main/resources/bootstrap.yml
+14
-0
zlt-demo/sso-demo/oidc-sso/src/main/resources/static/callback.html
...sso-demo/oidc-sso/src/main/resources/static/callback.html
+38
-0
zlt-demo/sso-demo/oidc-sso/src/main/resources/static/index.html
...mo/sso-demo/oidc-sso/src/main/resources/static/index.html
+49
-0
zlt-demo/sso-demo/oidc-sso/src/main/resources/static/js/jquery-3.2.1.min.js
...oidc-sso/src/main/resources/static/js/jquery-3.2.1.min.js
+4
-0
zlt-demo/sso-demo/oidc-sso/src/main/resources/static/js/sso.js
...emo/sso-demo/oidc-sso/src/main/resources/static/js/sso.js
+34
-0
zlt-demo/sso-demo/pom.xml
zlt-demo/sso-demo/pom.xml
+2
-0
zlt-demo/sso-demo/ss-sso/README.md
zlt-demo/sso-demo/ss-sso/README.md
+1
-1
zlt-demo/sso-demo/web-sso/README.md
zlt-demo/sso-demo/web-sso/README.md
+1
-1
未找到文件。
zlt-demo/sso-demo/README.md
浏览文件 @
6d3f8a75
*
**ss-sso**
:使用springSecurity来实现自动单点登录,非前后端分离
*
**web-sso**
:前后端分离的单点登录
*
**oidc-sso**
:拥有独立用户体系的系统,使用OIDC协议的单点登录
zlt-demo/sso-demo/oidc-sso/README.md
0 → 100644
浏览文件 @
6d3f8a75
## **详细的原理和注意事项请查看**
[
OIDC协议单点登录
](
https://www.kancloud.cn/zlt2000/microservices-platform/2278851
)
## oauth-center数据库执行以下sql
```
sql
alter
table
oauth_client_details
add
support_id_token
tinyint
(
1
)
DEFAULT
1
COMMENT
'是否支持id_token'
;
alter
table
oauth_client_details
add
id_token_validity
int
(
11
)
DEFAULT
60
COMMENT
'id_token有效期'
;
```
## 启动以下服务
1.
zlt-uaa:统一认证中心
2.
user-center:用户服务
3.
sc-gateway:api网关
4.
oidc-sso:单点登录demo(app应用)
5.
ss-sso:单点登录demo(zlt应用)
## 测试步骤
1.
登录zlt应用:
通过地址 http://127.0.0.1:8080 先登录zlt应用
2.
访问app应用(单点成功):
在浏览器打开一个新的页签(共享session),通过地址 http://127.0.0.1:8081/index.html 访问zlt应用静态页面,单点登录成功显示当前登录用户名、应用id、token信息
\ No newline at end of file
zlt-demo/sso-demo/oidc-sso/pom.xml
0 → 100644
浏览文件 @
6d3f8a75
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<parent>
<groupId>
com.zlt
</groupId>
<artifactId>
sso-demo
</artifactId>
<version>
4.4
</version>
</parent>
<artifactId>
oidc-sso
</artifactId>
<description>
OIDC协议单点登录demo
</description>
<dependencies>
<dependency>
<groupId>
cn.hutool
</groupId>
<artifactId>
hutool-all
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-web
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.cloud
</groupId>
<artifactId>
spring-cloud-context
</artifactId>
</dependency>
<dependency>
<groupId>
com.zlt
</groupId>
<artifactId>
zlt-common-core
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.security
</groupId>
<artifactId>
spring-security-jwt
</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
<executions>
<execution>
<goals>
<goal>
repackage
</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
zlt-demo/sso-demo/oidc-sso/src/main/java/com/sso/demo/OidcSSOApplication.java
0 → 100644
浏览文件 @
6d3f8a75
package
com.sso.demo
;
import
org.springframework.boot.SpringApplication
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
/**
* @author zlt
* @date 2020/5/22
* <p>
* Blog: https://zlt2000.gitee.io
* Github: https://github.com/zlt2000
*/
@SpringBootApplication
public
class
OidcSSOApplication
{
public
static
void
main
(
String
[]
args
)
{
SpringApplication
.
run
(
OidcSSOApplication
.
class
,
args
);
}
}
zlt-demo/sso-demo/oidc-sso/src/main/java/com/sso/demo/controller/ApiController.java
0 → 100644
浏览文件 @
6d3f8a75
package
com.sso.demo.controller
;
import
cn.hutool.core.util.RandomUtil
;
import
cn.hutool.core.util.StrUtil
;
import
com.central.common.model.Result
;
import
com.central.common.utils.JsonUtil
;
import
com.central.common.utils.RsaUtils
;
import
com.fasterxml.jackson.databind.JsonNode
;
import
lombok.Data
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.http.*
;
import
org.springframework.security.jwt.Jwt
;
import
org.springframework.security.jwt.JwtHelper
;
import
org.springframework.security.jwt.crypto.sign.RsaVerifier
;
import
org.springframework.security.jwt.crypto.sign.SignatureVerifier
;
import
org.springframework.util.Assert
;
import
org.springframework.util.LinkedMultiValueMap
;
import
org.springframework.util.MultiValueMap
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.client.RestTemplate
;
import
sun.misc.BASE64Encoder
;
import
java.nio.charset.StandardCharsets
;
import
java.security.interfaces.RSAPublicKey
;
import
java.util.*
;
/**
* @author zlt
* @date 2020/5/22
* <p>
* Blog: https://zlt2000.gitee.io
* Github: https://github.com/zlt2000
*/
@RestController
public
class
ApiController
{
private
static
final
String
PUBKEY_START
=
"-----BEGIN PUBLIC KEY-----"
;
private
static
final
String
PUBKEY_END
=
"-----END PUBLIC KEY-----"
;
@Value
(
"${zlt.sso.client-id:}"
)
private
String
clientId
;
@Value
(
"${zlt.sso.client-secret:}"
)
private
String
clientSecret
;
@Value
(
"${zlt.sso.redirect-uri:}"
)
private
String
redirectUri
;
@Value
(
"${zlt.sso.access-token-uri:}"
)
private
String
accessTokenUri
;
@Value
(
"${zlt.sso.jwt-key-uri:}"
)
private
String
jwtKeyUri
;
/**
* 公钥
*/
private
static
RSAPublicKey
publicKey
;
/**
* 模拟用户数据库
*/
private
static
final
Map
<
Long
,
MyUser
>
userDb
=
new
HashMap
<>();
/**
* nonce存储
*/
private
final
static
ThreadLocal
<
String
>
NONCE
=
new
ThreadLocal
<>();
@GetMapping
(
"/token/{code}"
)
public
Map
<
String
,
Object
>
tokenInfo
(
@PathVariable
String
code
)
throws
Exception
{
//获取token
Map
<
String
,
Object
>
tokenMap
=
getAccessToken
(
code
);
String
idTokenStr
=
(
String
)
tokenMap
.
get
(
"id_token"
);
//解析id_token
JsonNode
idToken
=
this
.
getIdTokenJson
(
idTokenStr
);
//检查id_token的有效性
checkToken
(
idToken
);
//获取用户信息
MyUser
user
=
this
.
getUserInfo
(
idToken
);
//判断用户信息是否存在,否则注册用户信息
if
(!
userDb
.
containsKey
(
user
.
getId
()))
{
userDb
.
put
(
user
.
getId
(),
user
);
}
Map
<
String
,
Object
>
result
=
new
HashMap
<>(
2
);
result
.
put
(
"tokenInfo"
,
tokenMap
);
result
.
put
(
"userInfo"
,
user
);
return
result
;
}
/**
* 检查 id_token 的有效性
*/
private
void
checkToken
(
JsonNode
idToken
)
{
//token有效期
long
expiresAt
=
idToken
.
get
(
"exp"
).
asLong
();
long
now
=
System
.
currentTimeMillis
();
Assert
.
isTrue
((
expiresAt
>
now
),
"id_token已过期"
);
//应用id
String
aud
=
idToken
.
get
(
"aud"
).
asText
();
Assert
.
isTrue
(
clientId
.
equals
(
aud
),
"非法应用"
+
aud
);
//随机码
String
nonce
=
idToken
.
get
(
"nonce"
).
asText
();
Assert
.
isTrue
((
StrUtil
.
isEmpty
(
nonce
)
||
nonce
.
equals
(
NONCE
.
get
())),
"nonce参数无效"
);
}
/**
* 获取token
*/
public
Map
<
String
,
Object
>
getAccessToken
(
String
code
)
{
RestTemplate
restTemplate
=
new
RestTemplate
();
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_FORM_URLENCODED
);
String
base64Auth
=
this
.
getBase64ClientParam
();
headers
.
add
(
"Authorization"
,
"Basic "
+
base64Auth
);
MultiValueMap
<
String
,
String
>
param
=
new
LinkedMultiValueMap
<>();
param
.
add
(
"code"
,
code
);
param
.
add
(
"grant_type"
,
"authorization_code"
);
param
.
add
(
"redirect_uri"
,
redirectUri
);
param
.
add
(
"scope"
,
"app"
);
param
.
add
(
"nonce"
,
this
.
genNonce
());
HttpEntity
<
MultiValueMap
<
String
,
String
>>
request
=
new
HttpEntity
<>(
param
,
headers
);
ResponseEntity
<
Map
>
response
=
restTemplate
.
postForEntity
(
accessTokenUri
,
request
,
Map
.
class
);
return
response
.
getBody
();
}
private
String
genNonce
()
{
String
nonce
=
RandomUtil
.
randomString
(
6
);
NONCE
.
set
(
nonce
);
return
nonce
;
}
/**
* 把 id_token 字符串解析为json对象
*/
public
JsonNode
getIdTokenJson
(
String
idToken
)
throws
Exception
{
RSAPublicKey
publicKey
=
getPubKeyObj
();
return
this
.
decodeAndVerify
(
idToken
,
publicKey
);
}
/**
* 通过 id_token 获取用户信息
*/
public
MyUser
getUserInfo
(
JsonNode
idToken
)
{
MyUser
user
=
new
MyUser
();
user
.
setId
(
Long
.
valueOf
(
idToken
.
get
(
"sub"
).
textValue
()));
user
.
setName
(
idToken
.
get
(
"name"
).
textValue
());
user
.
setLoginName
(
idToken
.
get
(
"login_name"
).
textValue
());
user
.
setPicture
(
idToken
.
get
(
"picture"
).
textValue
());
return
user
;
}
private
JsonNode
decodeAndVerify
(
String
jwtToken
,
RSAPublicKey
rsaPublicKey
)
{
SignatureVerifier
rsaVerifier
=
new
RsaVerifier
(
rsaPublicKey
);
Jwt
jwt
=
JwtHelper
.
decodeAndVerify
(
jwtToken
,
rsaVerifier
);
return
JsonUtil
.
parse
(
jwt
.
getClaims
());
}
/**
* 获取公钥
*/
public
RSAPublicKey
getPubKeyObj
()
throws
Exception
{
if
(
publicKey
==
null
)
{
publicKey
=
getPubKeyByRemote
();
}
return
publicKey
;
}
private
RSAPublicKey
getPubKeyByRemote
()
throws
Exception
{
HttpHeaders
headers
=
new
HttpHeaders
();
headers
.
setContentType
(
MediaType
.
APPLICATION_FORM_URLENCODED
);
String
base64Auth
=
this
.
getBase64ClientParam
();
headers
.
add
(
"Authorization"
,
"Basic "
+
base64Auth
);
HttpEntity
<
String
>
request
=
new
HttpEntity
<>(
headers
);
RestTemplate
restTemplate
=
new
RestTemplate
();
ResponseEntity
<
Result
>
response
=
restTemplate
.
exchange
(
jwtKeyUri
,
HttpMethod
.
GET
,
request
,
Result
.
class
);
Result
<
String
>
result
=
response
.
getBody
();
Assert
.
isTrue
((
result
.
getResp_code
()
==
200
),
result
.
getResp_msg
());
String
publicKeyStr
=
result
.
getResp_msg
();
publicKeyStr
=
publicKeyStr
.
substring
(
PUBKEY_START
.
length
(),
publicKeyStr
.
indexOf
(
PUBKEY_END
));
return
RsaUtils
.
getPublicKey
(
publicKeyStr
);
}
/**
* base64加密应用参数
*/
private
String
getBase64ClientParam
()
{
byte
[]
authorization
=
(
clientId
+
":"
+
clientSecret
).
getBytes
(
StandardCharsets
.
UTF_8
);
BASE64Encoder
encoder
=
new
BASE64Encoder
();
return
encoder
.
encode
(
authorization
);
}
@Data
public
static
class
MyUser
{
private
Long
id
;
private
String
name
;
private
String
loginName
;
private
String
picture
;
}
}
zlt-demo/sso-demo/oidc-sso/src/main/resources/bootstrap.yml
0 → 100644
浏览文件 @
6d3f8a75
server
:
port
:
8081
spring
:
application
:
name
:
oidc-demo
zlt
:
sso
:
client-id
:
app
client-secret
:
app
redirect-uri
:
http://127.0.0.1:8081/callback.html
access-token-uri
:
http://127.0.0.1:9900/api-uaa/oauth/token
jwt-key-uri
:
http://127.0.0.1:9900/api-uaa/tokens/key
\ No newline at end of file
zlt-demo/sso-demo/oidc-sso/src/main/resources/static/callback.html
0 → 100644
浏览文件 @
6d3f8a75
<!DOCTYPE html>
<html>
<head>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=edge,chrome=1"
>
<meta
charset=
"utf-8"
/>
<title>
zlt
</title>
<script
type=
"text/javascript"
src=
"js/jquery-3.2.1.min.js"
></script>
<script
type=
"text/javascript"
src=
"js/sso.js"
></script>
</head>
<body>
<script>
window
.
onload
=
function
()
{
//url获取state
let
state
=
getQueryVariable
(
'
state
'
);
let
localState
=
sessionStorage
.
getItem
(
"
state
"
);
//判断state防止CSRF攻击
if
(
localState
!==
state
)
{
alert
(
'
state参数无效!
'
);
let
state
=
getState
();
sessionStorage
.
setItem
(
"
state
"
,
state
);
window
.
location
=
getAuthorizeUri
(
state
);
}
//url获取code
let
code
=
getQueryVariable
(
'
code
'
);
//获取token和用户信息
$
.
ajax
({
url
:
'
http://127.0.0.1:8081/token/
'
+
code
,
success
:
function
(
result
)
{
console
.
log
(
result
);
sessionStorage
.
setItem
(
'
access_token
'
,
result
.
tokenInfo
.
access_token
);
sessionStorage
.
setItem
(
'
username
'
,
result
.
userInfo
.
name
);
sessionStorage
.
setItem
(
'
loginName
'
,
result
.
userInfo
.
loginName
);
sessionStorage
.
setItem
(
'
picture
'
,
result
.
userInfo
.
picture
);
window
.
location
=
sessionStorage
.
getItem
(
'
visitUri
'
);
}});
};
</script>
</body>
</html>
zlt-demo/sso-demo/oidc-sso/src/main/resources/static/index.html
0 → 100644
浏览文件 @
6d3f8a75
<!DOCTYPE html>
<html>
<head>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=edge,chrome=1"
>
<meta
charset=
"utf-8"
/>
<title>
zlt
</title>
<script
type=
"text/javascript"
src=
"js/jquery-3.2.1.min.js"
></script>
<script
type=
"text/javascript"
src=
"js/sso.js"
></script>
</head>
<body>
<div>
<p>
用户名:
<span
id=
"userName"
></span></p>
<p>
登录名:
<span
id=
"loginName"
></span></p>
<p>
头像:
<span
id=
"picture"
></span></p>
<p>
应用id:
<span
id=
"clientId"
></span></p>
<p>
token:
<span
id=
"accessToken"
></span></p>
<p><input
type=
"button"
value=
"登出"
onclick=
"logout()"
/></p>
</div>
<script>
window
.
onload
=
function
()
{
let
accessToken
=
sessionStorage
.
getItem
(
'
access_token
'
);
if
(
accessToken
)
{
//已登录
let
username
=
sessionStorage
.
getItem
(
'
username
'
);
let
loginName
=
sessionStorage
.
getItem
(
"
loginName
"
);
let
picture
=
sessionStorage
.
getItem
(
"
picture
"
);
$
(
'
#accessToken
'
).
html
(
accessToken
);
$
(
'
#userName
'
).
html
(
username
);
$
(
'
#loginName
'
).
html
(
loginName
);
$
(
'
#picture
'
).
html
(
picture
);
$
(
'
#clientId
'
).
html
(
clientId
);
}
else
{
//未登录
let
state
=
getState
();
sessionStorage
.
setItem
(
"
visitUri
"
,
window
.
location
.
href
);
sessionStorage
.
setItem
(
"
state
"
,
state
);
window
.
location
=
getAuthorizeUri
(
state
);
}
};
function
logout
()
{
let
accessToken
=
sessionStorage
.
getItem
(
'
access_token
'
);
sessionStorage
.
removeItem
(
'
access_token
'
);
sessionStorage
.
removeItem
(
'
username
'
);
sessionStorage
.
removeItem
(
"
loginName
"
);
sessionStorage
.
removeItem
(
"
picture
"
);
window
.
location
=
getLogoutUri
(
accessToken
);
}
</script>
</body>
</html>
zlt-demo/sso-demo/oidc-sso/src/main/resources/static/js/jquery-3.2.1.min.js
0 → 100644
浏览文件 @
6d3f8a75
此差异已折叠。
点击以展开。
zlt-demo/sso-demo/oidc-sso/src/main/resources/static/js/sso.js
0 → 100644
浏览文件 @
6d3f8a75
const
FULL_CHARTER
=
'
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopgrstuvwxyz
'
;
//应用id
let
clientId
=
'
app
'
;
//授权中心地址
let
uaaUri
=
'
http://127.0.0.1:9900/api-uaa/oauth/
'
;
function
getAuthorizeUri
(
state
)
{
return
uaaUri
+
'
authorize?client_id=
'
+
clientId
+
'
&redirect_uri=http://127.0.0.1:8081/callback.html&response_type=code%20id_token&state=
'
+
state
;
}
function
getLogoutUri
(
accessToken
)
{
return
uaaUri
+
'
remove/token?redirect_uri=http://127.0.0.1:8081/index.html&access_token=
'
+
accessToken
;
}
function
getState
()
{
let
state
=
''
;
for
(
let
i
=
0
;
i
<
6
;
i
++
)
{
state
+=
FULL_CHARTER
[
Math
.
floor
(
Math
.
random
()
*
52
)];
}
return
state
;
}
/**
* 获取url参数
*/
function
getQueryVariable
(
variable
)
{
var
query
=
window
.
location
.
search
.
substring
(
1
);
var
vars
=
query
.
split
(
"
&
"
);
for
(
var
i
=
0
;
i
<
vars
.
length
;
i
++
)
{
var
pair
=
vars
[
i
].
split
(
"
=
"
);
if
(
pair
[
0
]
==
variable
){
return
pair
[
1
];}
}
return
''
;
}
\ No newline at end of file
zlt-demo/sso-demo/pom.xml
浏览文件 @
6d3f8a75
...
...
@@ -14,5 +14,7 @@
<module>
ss-sso
</module>
<!-- 前后端分离单点登录demo -->
<module>
web-sso
</module>
<!-- OIDC协议单点登录demo -->
<module>
oidc-sso
</module>
</modules>
</project>
\ No newline at end of file
zlt-demo/sso-demo/ss-sso/README.md
浏览文件 @
6d3f8a75
## **详细的原理和注意事项请查看**
[
单点登录详解
](
https://www.kancloud.cn/zlt2000/microservices-platform/
1515193
)
[
单点登录详解
](
https://www.kancloud.cn/zlt2000/microservices-platform/
2278849
)
...
...
zlt-demo/sso-demo/web-sso/README.md
浏览文件 @
6d3f8a75
## **详细的原理和注意事项请查看**
[
单点登录详解
](
https://www.kancloud.cn/zlt2000/microservices-platform/1515193
)
[
前后端分离的单点登录
](
https://www.kancloud.cn/zlt2000/microservices-platform/2278850
)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录