├── .gitattributes
├── maven-version-rules.xml
├── src
├── main
│ ├── java
│ │ └── com
│ │ │ └── revengemission
│ │ │ └── sso
│ │ │ └── oauth2
│ │ │ └── client
│ │ │ ├── Oauth2ClientApplication.java
│ │ │ ├── controller
│ │ │ └── FrontIndexController.java
│ │ │ └── config
│ │ │ ├── CustomAuthenticationSuccessHandler.java
│ │ │ ├── RefreshExpiredTokenFilter.java
│ │ │ └── SecurityConfig.java
│ └── resources
│ │ ├── templates
│ │ ├── index.html
│ │ └── securedPage.html
│ │ ├── application.properties
│ │ └── static
│ │ └── assets
│ │ └── localforage.min.js
└── test
│ └── java
│ └── com
│ └── revengemission
│ └── sso
│ └── oauth2
│ └── client
│ └── ApplicationTests.java
├── .editorconfig
├── LICENSE
├── README.md
├── .gitignore
└── pom.xml
/.gitattributes:
--------------------------------------------------------------------------------
1 |
2 | text=lf
3 |
--------------------------------------------------------------------------------
/maven-version-rules.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 | .*[-_\.](alpha|Alpha|ALPHA|b|beta|Beta|BETA|rc|RC|M|EA)[-_\.]?[0-9]*
7 |
8 |
--------------------------------------------------------------------------------
/src/main/java/com/revengemission/sso/oauth2/client/Oauth2ClientApplication.java:
--------------------------------------------------------------------------------
1 | package com.revengemission.sso.oauth2.client;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | /**
7 | * https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#oauth2client
8 | */
9 | @SpringBootApplication
10 | public class Oauth2ClientApplication {
11 |
12 | public static void main(String[] args) {
13 | SpringApplication.run(Oauth2ClientApplication.class, args);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/resources/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | spring security oauth2 client
6 |
7 |
8 |
9 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 |
2 |
3 | # EditorConfig is awesome: https://EditorConfig.org
4 |
5 | # top-most EditorConfig file
6 | root = true
7 |
8 | # Unix-style newlines with a newline ending every file
9 | [*]
10 | end_of_line = lf
11 | insert_final_newline = true
12 | charset = utf-8
13 |
14 | [*.java]
15 | indent_style = space
16 | indent_size = 4
17 |
18 | # Matches multiple files with brace expansion notation
19 | # Set default charset
20 | [*.{js,py}]
21 | charset = utf-8
22 |
23 | # 4 space indentation
24 | [*.py]
25 | indent_style = space
26 | indent_size = 4
27 |
28 | # Tab indentation (no size specified)
29 | [Makefile]
30 | indent_style = tab
31 |
32 | # Indentation override for all JS under lib directory
33 | [lib/**.js]
34 | indent_style = space
35 | indent_size = 2
36 |
37 | # Matches the exact files either package.json or .travis.yml
38 | [{package.json,.travis.yml}]
39 | indent_style = space
40 | indent_size = 2
41 |
42 |
--------------------------------------------------------------------------------
/src/main/resources/templates/securedPage.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | Spring Security SSO
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Secured Page
14 | Welcome, Name
15 | authorities, Authorities
16 |
17 |
18 |
19 |
20 | 超级用户
21 |
22 |
23 |
24 | 普通用户
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 mission
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 基于spring boot2 sso Oauth2 Client JWT
2 | ## 启动前修改application.properties中的相关参数
3 | ### 当client和server在一台主机时,请用域名访问,否则cookies会相互覆盖,影响测试,以下配置仅供参考
4 | * hosts文件
5 | ````hosts
6 | 127.0.0.1 client.sso.com
7 | 127.0.0.1 server.sso.com
8 | ````
9 | * nginx配置
10 | ````nginx
11 | server {
12 | server_name client.sso.com;
13 | listen 80;
14 | listen [::]:80;
15 |
16 | proxy_set_header Host $host;
17 | proxy_set_header X-Real-IP $remote_addr;
18 | proxy_set_header REMOTE-HOST $remote_addr;
19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
20 |
21 |
22 | index index.html;
23 |
24 | location / {
25 | proxy_pass http://localhost:10480/;
26 | }
27 | }
28 |
29 | server {
30 | server_name server.sso.com;
31 | listen 80;
32 | listen [::]:80;
33 |
34 | proxy_set_header Host $host;
35 | proxy_set_header X-Real-IP $remote_addr;
36 | proxy_set_header REMOTE-HOST $remote_addr;
37 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
38 |
39 |
40 | index index.html;
41 |
42 | location / {
43 | proxy_pass http://localhost:10380/;
44 | }
45 | }
46 | ````
47 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=10480
2 |
3 | server.servlet.session.cookie.name=my_session_id
4 |
5 | spring.security.oauth2.client.registration.sso-login.provider=sso-provider
6 | spring.security.oauth2.client.registration.sso-login.client-id=SampleClientId
7 | spring.security.oauth2.client.registration.sso-login.client-name=sample client application
8 | spring.security.oauth2.client.registration.sso-login.client-secret=tgb.258
9 | spring.security.oauth2.client.registration.sso-login.client-authentication-method=client_secret_post
10 | spring.security.oauth2.client.registration.sso-login.authorization-grant-type=authorization_code
11 | spring.security.oauth2.client.registration.sso-login.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
12 | spring.security.oauth2.client.registration.sso-login.scope=profile
13 |
14 | spring.security.oauth2.client.provider.sso-provider.authorization-uri=http://localhost:35080/oauth2/authorize
15 | spring.security.oauth2.client.provider.sso-provider.token-uri=http://localhost:35080/oauth2/token
16 | spring.security.oauth2.client.provider.sso-provider.user-info-uri=http://localhost:35080/user/me
17 | spring.security.oauth2.client.provider.sso-provider.user-name-attribute=sub
18 |
19 | spring.thymeleaf.cache=false
20 | logging.level.root=info
21 | logging.level.org.springframework.security=debug
22 | logging.file.path=/data/logs/oauth2-client
23 | logging.file.max-history=45
24 |
25 | host.api=http://api.sso.com
26 | oauth2.token.cookie.domain=sso.com
27 |
--------------------------------------------------------------------------------
/src/test/java/com/revengemission/sso/oauth2/client/ApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.revengemission.sso.oauth2.client;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import com.fasterxml.jackson.databind.SerializationFeature;
5 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
6 | import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
7 | import org.junit.jupiter.api.Disabled;
8 | import org.junit.jupiter.api.Test;
9 | import org.springframework.boot.test.context.SpringBootTest;
10 | import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
11 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
12 | import org.springframework.web.client.RestTemplate;
13 |
14 | import java.time.LocalDateTime;
15 | import java.time.format.DateTimeFormatter;
16 |
17 | @SpringBootTest
18 | public class ApplicationTests {
19 |
20 | @Disabled
21 | @Test
22 | public void contextLoads() {
23 |
24 | //用登陆后的token ,请求api资源
25 | //header格式,Authorization : Bearer xxxxx
26 |
27 | RestTemplate restTemplate = new RestTemplate();
28 | JavaTimeModule module = new JavaTimeModule();
29 | LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(
30 | DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
31 | module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
32 |
33 | ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().modules(module)
34 | .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).build();
35 |
36 | MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
37 | jsonMessageConverter.setObjectMapper(objectMapper);
38 | restTemplate.getMessageConverters().add(0, jsonMessageConverter);
39 |
40 | // request some api
41 |
42 |
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ######################
2 | # Project Specific
3 | ######################
4 | /target/www/**
5 |
6 | ######################
7 | # Node
8 | ######################
9 | /node/**
10 | /node_tmp/**
11 | /node_modules/**
12 |
13 | ######################
14 | # SASS
15 | ######################
16 | .sass-cache/**
17 |
18 | ######################
19 | # Eclipse
20 | ######################
21 | *.pydevproject
22 | .project
23 | .metadata
24 | /bin/**
25 | /tmp/**
26 | /tmp/**/*
27 | *.tmp
28 | *.bak
29 | *.swp
30 | *~.nib
31 | local.properties
32 | .classpath
33 | .settings/**
34 | .loadpath
35 | /src/main/resources/rebel.xml
36 |
37 | # External tool builders
38 | .externalToolBuilders/**
39 |
40 | # Locally stored "Eclipse launch configurations"
41 | *.launch
42 |
43 | # CDT-specific
44 | .cproject
45 |
46 | # PDT-specific
47 | .buildpath
48 |
49 | ######################
50 | # Intellij
51 | ######################
52 | .idea/
53 | *.iml
54 | *.iws
55 | *.ipr
56 | *.ids
57 | *.orig
58 | **/target/**
59 |
60 | ######################
61 | # Maven
62 | ######################
63 | /log/**
64 | /target/**
65 |
66 | ######################
67 | # Gradle
68 | ######################
69 | .gradle/**
70 |
71 | ######################
72 | # Package Files
73 | ######################
74 | *.jar
75 | *.war
76 | *.ear
77 | *.db
78 |
79 | ######################
80 | # Windows
81 | ######################
82 | # Windows image file caches
83 | Thumbs.db
84 |
85 | # Folder config file
86 | Desktop.ini
87 |
88 | ######################
89 | # Mac OSX
90 | ######################
91 | .DS_Store
92 | .svn
93 |
94 | # Thumbnails
95 | ._*
96 |
97 | # Files that might appear on external disk
98 | .Spotlight-V100
99 | .Trashes
100 |
101 | ######################
102 | # Directories
103 | ######################
104 | /build/**
105 | /bin/
106 | /spring_loaded/**
107 | /deploy/**
108 |
109 | ######################
110 | # Logs
111 | ######################
112 | *.log
113 |
114 | ######################
115 | # Others
116 | ######################
117 | *.class
118 | *.*~
119 | *~
120 | .merge_file*
121 |
122 | ######################
123 | # Gradle Wrapper
124 | ######################
125 | !gradle/wrapper/gradle-wrapper.jar
126 |
127 | ######################
128 | # Maven Wrapper
129 | ######################
130 | !.mvn/wrapper/maven-wrapper.jar
131 |
132 | ######################
133 | # ESLint
134 | ######################
135 | .eslintcache
--------------------------------------------------------------------------------
/src/main/java/com/revengemission/sso/oauth2/client/controller/FrontIndexController.java:
--------------------------------------------------------------------------------
1 | package com.revengemission.sso.oauth2.client.controller;
2 |
3 | import org.springframework.boot.web.client.RestTemplateBuilder;
4 | import org.springframework.http.HttpEntity;
5 | import org.springframework.http.HttpHeaders;
6 | import org.springframework.http.HttpMethod;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.security.core.Authentication;
9 | import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
10 | import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
11 | import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
12 | import org.springframework.stereotype.Controller;
13 | import org.springframework.ui.Model;
14 | import org.springframework.web.bind.annotation.GetMapping;
15 | import org.springframework.web.bind.annotation.ResponseBody;
16 | import org.springframework.web.client.RestTemplate;
17 |
18 |
19 | @Controller
20 | public class FrontIndexController {
21 |
22 | RestTemplate restTemplate;
23 |
24 | public FrontIndexController(RestTemplateBuilder restTemplateBuilder) {
25 | super();
26 | //可以全局配置converter等
27 | this.restTemplate = restTemplateBuilder.build();
28 | }
29 |
30 | @GetMapping(value = {"/", "/index"})
31 | public String index(Authentication authentication,
32 | Model model) {
33 | return "index";
34 | }
35 |
36 | @GetMapping(value = "/user")
37 | public String user(OAuth2AuthenticationToken oAuth2AuthenticationToken,
38 | Authentication authentication,
39 | @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,
40 | Model model) {
41 | model.addAttribute("authentication", authentication);
42 | return "securedPage";
43 | }
44 |
45 | @ResponseBody
46 | @GetMapping(value = "/resource")
47 | public Object resource(OAuth2AuthenticationToken oAuth2AuthenticationToken,
48 | @RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,
49 | Model model) {
50 | String url = "http://localhost:10580/coupon/list";
51 | HttpHeaders headers = new HttpHeaders();
52 | headers.add("Authorization", "Bearer " + authorizedClient.getAccessToken().getTokenValue());
53 | ResponseEntity