├── .gitignore
├── springsecurity101-cloud-oauth2-userservice
├── src
│ └── main
│ │ ├── resources
│ │ ├── application.yml
│ │ └── public.cert
│ │ └── java
│ │ └── me
│ │ └── josephzhu
│ │ └── springsecurity101
│ │ └── cloud
│ │ └── oauth2
│ │ └── userservice
│ │ ├── HelloController.java
│ │ ├── UserServiceApplication.java
│ │ ├── UserController.java
│ │ └── ResourceServerConfiguration.java
└── pom.xml
├── springsecurity101-cloud-oauth2-server
├── src
│ └── main
│ │ ├── resources
│ │ ├── jwt.jks
│ │ ├── application.yml
│ │ └── templates
│ │ │ └── login.html
│ │ └── java
│ │ └── me
│ │ └── josephzhu
│ │ └── springsecurity101
│ │ └── cloud
│ │ └── oauth2
│ │ └── server
│ │ ├── OAuth2ServerApplication.java
│ │ ├── CustomTokenEnhancer.java
│ │ ├── WebSecurityConfig.java
│ │ └── OAuth2ServerConfiguration.java
└── pom.xml
├── docker-compose.yml
├── springsecurity101-cloud-oauth2-client
├── src
│ └── main
│ │ ├── java
│ │ └── me
│ │ │ └── josephzhu
│ │ │ └── springsecurity101
│ │ │ └── cloud
│ │ │ └── auth
│ │ │ └── client
│ │ │ ├── OAuth2ClientApplication.java
│ │ │ ├── WebSecurityConfig.java
│ │ │ ├── DemoController.java
│ │ │ ├── OAuthClientConfig.java
│ │ │ └── WebMvcConfig.java
│ │ └── resources
│ │ ├── templates
│ │ ├── index.html
│ │ └── securedPage.html
│ │ └── application.yml
└── pom.xml
├── pom.xml
└── oauth.sql
/.gitignore:
--------------------------------------------------------------------------------
1 | */target
2 | .idea
3 | *.iml
4 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-userservice/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8081
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-server/src/main/resources/jwt.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JosephZhu1983/SpringSecurity101/HEAD/springsecurity101-cloud-oauth2-server/src/main/resources/jwt.jks
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-server/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8080
3 |
4 | spring:
5 | application:
6 | name: oauth2-server
7 | datasource:
8 | url: jdbc:mysql://localhost:6657/oauth?useSSL=false
9 | username: root
10 | password: kIo9u7Oi0eg
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3.6"
2 | services:
3 | redis:
4 | image: redis:3
5 | container_name: oauth2-redis-3
6 | command: redis-server --appendonly yes
7 | ports:
8 | - "6379:6379"
9 | mysql57:
10 | image: mysql:5.7
11 | container_name: oauth2-mysql57
12 | environment:
13 | MYSQL_ROOT_PASSWORD: kIo9u7Oi0eg
14 | ports:
15 | - "6657:3306"
16 | volumes:
17 | - ./mysql-init:/docker-entrypoint-initdb.d/
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-userservice/src/main/java/me/josephzhu/springsecurity101/cloud/oauth2/userservice/HelloController.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.oauth2.userservice;
2 |
3 | import org.springframework.web.bind.annotation.GetMapping;
4 | import org.springframework.web.bind.annotation.RestController;
5 |
6 | @RestController
7 | public class HelloController {
8 | @GetMapping("hello")
9 | public String hello() {
10 | return "Hello";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/src/main/java/me/josephzhu/springsecurity101/cloud/auth/client/OAuth2ClientApplication.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.auth.client;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class OAuth2ClientApplication {
8 | public static void main(String[] args) {
9 | SpringApplication.run(OAuth2ClientApplication.class, args);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-server/src/main/java/me/josephzhu/springsecurity101/cloud/oauth2/server/OAuth2ServerApplication.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.oauth2.server;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class OAuth2ServerApplication {
8 | public static void main(String[] args) {
9 | SpringApplication.run(OAuth2ServerApplication.class, args);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-userservice/src/main/resources/public.cert:
--------------------------------------------------------------------------------
1 | -----BEGIN PUBLIC KEY-----
2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwR84LFHwnK5GXErnwkmD
3 | mPOJl4CSTtYXCqmCtlbF+5qVOosu0YsM2DsrC9O2gun6wVFKkWYiMoBSjsNMSI3Z
4 | w5JYgh+ldHvA+MIex2QXfOZx920M1fPUiuUPgmnTFS+Z3lmK3/T6jJnmciUPY1pe
5 | h4MXL6YzeI0q4W9xNBBeKT6FDGpduc0FC3OlXHfLbVOThKmAUpAWFDwf9/uUA//l
6 | 3PLchmV6VwTcUaaHp5W8Af/GU4lPGZbTAqOxzB9ukisPFuO1DikacPhrOQgdxtqk
7 | LciRTa884uQnkFwSguOEUYf3ni8GNRJauIuW0rVXhMOs78pKvCKmo53M0tqeC6ul
8 | +QIDAQAB
9 | -----END PUBLIC KEY-----
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-userservice/src/main/java/me/josephzhu/springsecurity101/cloud/oauth2/userservice/UserServiceApplication.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.oauth2.userservice;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class UserServiceApplication {
8 | public static void main(String[] args) {
9 | SpringApplication.run(UserServiceApplication.class, args);
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/src/main/resources/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Spring Security SSO Client
6 |
8 |
9 |
10 |
11 |
12 |
13 |
Spring Security SSO Client
14 |
Login
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/src/main/resources/templates/securedPage.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Spring Security SSO Client
6 |
8 |
9 |
10 |
11 |
12 |
13 |
Secured Page
14 | Welcome, Name
15 |
16 | Your authorities are authorities
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-userservice/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springsecurity101
7 | me.josephzhu
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | springsecurity101-cloud-oauth2-userservice
13 |
14 |
15 |
16 | org.springframework.cloud
17 | spring-cloud-starter-oauth2
18 |
19 |
20 | org.springframework.boot
21 | spring-boot-starter-web
22 |
23 |
24 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/src/main/java/me/josephzhu/springsecurity101/cloud/auth/client/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.auth.client;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.core.annotation.Order;
5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
7 |
8 | @Configuration
9 | @Order(200)
10 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
11 | /**
12 | * /路径和/login路径允许访问,其它路径需要身份认证后才能访问
13 | *
14 | * @param http
15 | * @throws Exception
16 | */
17 | @Override
18 | protected void configure(HttpSecurity http) throws Exception {
19 | http
20 | .authorizeRequests()
21 | .antMatchers("/", "/login**")
22 | .permitAll()
23 | .anyRequest()
24 | .authenticated();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8083
3 | servlet:
4 | context-path: /ui
5 | security:
6 | oauth2:
7 | client:
8 | clientId: userservice3
9 | clientSecret: 1234
10 | accessTokenUri: http://localhost:8080/oauth/token
11 | userAuthorizationUri: http://localhost:8080/oauth/authorize
12 | scope: FOO
13 | resource:
14 | jwt:
15 | key-value: |
16 | -----BEGIN PUBLIC KEY-----
17 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwR84LFHwnK5GXErnwkmD
18 | mPOJl4CSTtYXCqmCtlbF+5qVOosu0YsM2DsrC9O2gun6wVFKkWYiMoBSjsNMSI3Z
19 | w5JYgh+ldHvA+MIex2QXfOZx920M1fPUiuUPgmnTFS+Z3lmK3/T6jJnmciUPY1pe
20 | h4MXL6YzeI0q4W9xNBBeKT6FDGpduc0FC3OlXHfLbVOThKmAUpAWFDwf9/uUA//l
21 | 3PLchmV6VwTcUaaHp5W8Af/GU4lPGZbTAqOxzB9ukisPFuO1DikacPhrOQgdxtqk
22 | LciRTa884uQnkFwSguOEUYf3ni8GNRJauIuW0rVXhMOs78pKvCKmo53M0tqeC6ul
23 | +QIDAQAB
24 | -----END PUBLIC KEY-----
25 | spring:
26 | thymeleaf:
27 | cache: false
28 |
29 | #logging:
30 | # level:
31 | # ROOT: DEBUG
32 |
33 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | springsecurity101
8 | me.josephzhu
9 | 1.0-SNAPSHOT
10 |
11 |
12 | springsecurity101-cloud-oauth2-client
13 | 4.0.0
14 |
15 |
16 |
17 | org.springframework.cloud
18 | spring-cloud-starter-oauth2
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-web
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-thymeleaf
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/src/main/java/me/josephzhu/springsecurity101/cloud/auth/client/DemoController.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.auth.client;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.http.ResponseEntity;
5 | import org.springframework.security.oauth2.client.OAuth2RestTemplate;
6 | import org.springframework.security.oauth2.provider.OAuth2Authentication;
7 | import org.springframework.web.bind.annotation.GetMapping;
8 | import org.springframework.web.bind.annotation.RestController;
9 | import org.springframework.web.servlet.ModelAndView;
10 |
11 | @RestController
12 | public class DemoController {
13 | @Autowired
14 | OAuth2RestTemplate restTemplate;
15 |
16 | @GetMapping("/securedPage")
17 | public ModelAndView securedPage(OAuth2Authentication authentication) {
18 | return new ModelAndView("securedPage").addObject("authentication", authentication);
19 | }
20 |
21 | @GetMapping("/remoteCall")
22 | public String remoteCall() {
23 | ResponseEntity responseEntity = restTemplate.getForEntity("http://localhost:8081/user/name", String.class);
24 | return responseEntity.getBody();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/src/main/java/me/josephzhu/springsecurity101/cloud/auth/client/OAuthClientConfig.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.auth.client;
2 |
3 | import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.security.oauth2.client.OAuth2ClientContext;
7 | import org.springframework.security.oauth2.client.OAuth2RestTemplate;
8 | import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
9 |
10 | @Configuration
11 | @EnableOAuth2Sso //这个注解包含了@EnableOAuth2Client
12 | public class OAuthClientConfig {
13 | /**
14 | * 定义了OAuth2RestTemplate,网上一些比较老的资料给出的是手动读取配置文件来实现,最新版本已经可以自动注入OAuth2ProtectedResourceDetails
15 | *
16 | * @param oAuth2ClientContext
17 | * @param details
18 | * @return
19 | */
20 | @Bean
21 | public OAuth2RestTemplate oauth2RestTemplate(OAuth2ClientContext oAuth2ClientContext,
22 | OAuth2ProtectedResourceDetails details) {
23 | return new OAuth2RestTemplate(details, oAuth2ClientContext);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-client/src/main/java/me/josephzhu/springsecurity101/cloud/auth/client/WebMvcConfig.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.auth.client;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.context.request.RequestContextListener;
6 | import org.springframework.web.servlet.config.annotation.EnableWebMvc;
7 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9 |
10 | @Configuration
11 | @EnableWebMvc
12 | public class WebMvcConfig implements WebMvcConfigurer {
13 |
14 | /**
15 | * 配置RequestContextListener用于启用session scope的Bean
16 | *
17 | * @return
18 | */
19 | @Bean
20 | public RequestContextListener requestContextListener() {
21 | return new RequestContextListener();
22 | }
23 |
24 | /**
25 | * 配置index路径的首页Controller
26 | * @param registry
27 | */
28 | @Override
29 | public void addViewControllers(ViewControllerRegistry registry) {
30 | registry.addViewController("/")
31 | .setViewName("forward:/index");
32 | registry.addViewController("/index");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-server/src/main/java/me/josephzhu/springsecurity101/cloud/oauth2/server/CustomTokenEnhancer.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.oauth2.server;
2 |
3 | import org.springframework.security.core.Authentication;
4 | import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
5 | import org.springframework.security.oauth2.common.OAuth2AccessToken;
6 | import org.springframework.security.oauth2.provider.OAuth2Authentication;
7 | import org.springframework.security.oauth2.provider.token.TokenEnhancer;
8 |
9 | import java.util.HashMap;
10 | import java.util.Map;
11 |
12 | public class CustomTokenEnhancer implements TokenEnhancer {
13 |
14 | @Override
15 | public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
16 | Authentication userAuthentication = authentication.getUserAuthentication();
17 | if (userAuthentication != null) {
18 | Object principal = authentication.getUserAuthentication().getPrincipal();
19 | //把用户标识以userDetails这个Key加入到JWT的额外信息中去
20 | Map additionalInfo = new HashMap<>();
21 | additionalInfo.put("userDetails", principal);
22 | ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
23 | }
24 | return accessToken;
25 | }
26 | }
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-server/src/main/resources/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | OAuth2 Demo
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Login Form
14 |
15 |
16 | 用户名或密码错误...
17 |
18 |
19 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springsecurity101
7 | me.josephzhu
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | springsecurity101-cloud-oauth2-server
13 |
14 |
15 |
16 | org.springframework.cloud
17 | spring-cloud-starter-oauth2
18 |
19 |
20 | org.springframework.boot
21 | spring-boot-starter-jdbc
22 |
23 |
24 | mysql
25 | mysql-connector-java
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter-web
30 |
31 |
32 | org.springframework.boot
33 | spring-boot-starter-thymeleaf
34 |
35 |
36 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | me.josephzhu
8 | springsecurity101
9 | pom
10 | 1.0-SNAPSHOT
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 2.2.1.RELEASE
16 |
17 |
18 |
19 |
20 | springsecurity101-cloud-oauth2-client
21 | springsecurity101-cloud-oauth2-server
22 | springsecurity101-cloud-oauth2-userservice
23 |
24 |
25 |
26 | UTF-8
27 | UTF-8
28 | 1.8
29 |
30 |
31 |
32 |
33 | org.projectlombok
34 | lombok
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 | org.springframework.cloud
43 | spring-cloud-dependencies
44 | Greenwich.SR4
45 | pom
46 | import
47 |
48 |
49 |
50 |
51 |
52 |
53 | org.springframework.boot
54 | spring-boot-maven-plugin
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-server/src/main/java/me/josephzhu/springsecurity101/cloud/oauth2/server/WebSecurityConfig.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.oauth2.server;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.security.authentication.AuthenticationManager;
7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
10 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
11 |
12 | import javax.sql.DataSource;
13 |
14 |
15 | @Configuration
16 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
17 | @Autowired
18 | private DataSource dataSource;
19 |
20 | @Override
21 | @Bean
22 | public AuthenticationManager authenticationManagerBean() throws Exception {
23 | return super.authenticationManagerBean();
24 | }
25 |
26 | /**
27 | * 配置用户账户的认证方式,显然,我们把用户存在了数据库中希望配置JDBC的方式。
28 | * 此外,我们还配置了使用BCryptPasswordEncoder哈希来保存用户的密码(生产环境的用户密码肯定不能是明文保存)
29 | *
30 | * @param auth
31 | * @throws Exception
32 | */
33 | @Override
34 | protected void configure(AuthenticationManagerBuilder auth) throws Exception {
35 | auth.jdbcAuthentication()
36 | .dataSource(dataSource)
37 | .passwordEncoder(new BCryptPasswordEncoder());
38 | }
39 |
40 | /**
41 | * 开放/login和/oauth/authorize两个路径的匿名访问,前者用于登录,后者用于换授权码,这两个端点访问的时候都在登录之前。
42 | * 设置/login使用表单验证进行登录。
43 | * @param http
44 | * @throws Exception
45 | */
46 | @Override
47 | protected void configure(HttpSecurity http) throws Exception {
48 | http.authorizeRequests()
49 | .antMatchers("/login", "/oauth/authorize")
50 | .permitAll()
51 | .anyRequest().authenticated()
52 | .and()
53 | .formLogin().loginPage("/login");
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-userservice/src/main/java/me/josephzhu/springsecurity101/cloud/oauth2/userservice/UserController.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.oauth2.userservice;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.security.access.prepost.PreAuthorize;
5 | import org.springframework.security.oauth2.common.OAuth2AccessToken;
6 | import org.springframework.security.oauth2.provider.OAuth2Authentication;
7 | import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
8 | import org.springframework.security.oauth2.provider.token.TokenStore;
9 | import org.springframework.web.bind.annotation.GetMapping;
10 | import org.springframework.web.bind.annotation.PostMapping;
11 | import org.springframework.web.bind.annotation.RequestMapping;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | @RestController
15 | @RequestMapping("user")
16 | public class UserController {
17 |
18 | @Autowired
19 | private TokenStore tokenStore;
20 |
21 | /***
22 | * 读权限或写权限可访问,返回登录用户名
23 | * @param authentication
24 | * @return
25 | */
26 | @PreAuthorize("hasAuthority('READ') or hasAuthority('WRITE')")
27 | @GetMapping("name")
28 | public String name(OAuth2Authentication authentication) {
29 | return authentication.getName();
30 | }
31 |
32 | /**
33 | * 读权限或写权限可访问,返回登录用户信息
34 | *
35 | * @param authentication
36 | * @return
37 | */
38 | @PreAuthorize("hasAuthority('READ') or hasAuthority('WRITE')")
39 | @GetMapping
40 | public OAuth2Authentication read(OAuth2Authentication authentication) {
41 | return authentication;
42 | }
43 |
44 | /**
45 | * 只有写权限可以访问,返回访问令牌中的额外信息
46 | * @param authentication
47 | * @return
48 | */
49 | @PreAuthorize("hasAuthority('WRITE')")
50 | @PostMapping
51 | public Object write(OAuth2Authentication authentication) {
52 | OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
53 | OAuth2AccessToken accessToken = tokenStore.readAccessToken(details.getTokenValue());
54 | return accessToken.getAdditionalInformation().getOrDefault("userDetails", null);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-userservice/src/main/java/me/josephzhu/springsecurity101/cloud/oauth2/userservice/ResourceServerConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.oauth2.userservice;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.core.io.ClassPathResource;
6 | import org.springframework.core.io.Resource;
7 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
9 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
10 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
11 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
12 | import org.springframework.security.oauth2.provider.token.TokenStore;
13 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
14 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
15 | import org.springframework.util.FileCopyUtils;
16 |
17 | import java.io.IOException;
18 |
19 | @Configuration
20 | @EnableResourceServer //启用资源服务器
21 | @EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法注解方式来进行权限控制
22 | public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
23 |
24 | /**
25 | * 声明了资源服务器的ID是userservice,声明了资源服务器的TokenStore是JWT
26 | * @param resources
27 | * @throws Exception
28 | */
29 | @Override
30 | public void configure(ResourceServerSecurityConfigurer resources) {
31 | resources.resourceId("userservice").tokenStore(tokenStore());
32 | }
33 |
34 | /**
35 | * 配置TokenStore
36 | *
37 | * @return
38 | */
39 | @Bean
40 | public TokenStore tokenStore() {
41 | return new JwtTokenStore(jwtAccessTokenConverter());
42 | }
43 |
44 | /**
45 | * 配置公钥
46 | * @return
47 | */
48 | @Bean
49 | protected JwtAccessTokenConverter jwtAccessTokenConverter() {
50 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
51 | Resource resource = new ClassPathResource("public.cert");
52 | String publicKey = null;
53 | try {
54 | publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
55 | } catch (IOException e) {
56 | e.printStackTrace();
57 | }
58 | converter.setVerifierKey(publicKey);
59 | return converter;
60 | }
61 |
62 | /**
63 | * 配置了除了/user路径之外的请求可以匿名访问
64 | * @param http
65 | * @throws Exception
66 | */
67 | @Override
68 | public void configure(HttpSecurity http) throws Exception {
69 | http.authorizeRequests()
70 | .antMatchers("/user/**").authenticated()
71 | .anyRequest().permitAll();
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/oauth.sql:
--------------------------------------------------------------------------------
1 |
2 |
3 | SET NAMES utf8mb4;
4 | SET FOREIGN_KEY_CHECKS = 0;
5 |
6 | -- ----------------------------
7 | -- Table structure for authorities
8 | -- ----------------------------
9 | drop table IF EXISTS `authorities`;
10 | create TABLE `authorities` (
11 | `username` varchar(50) NOT NULL,
12 | `authority` varchar(50) NOT NULL,
13 | UNIQUE KEY `ix_auth_username` (`username`,`authority`),
14 | CONSTRAINT `fk_authorities_users` FOREIGN KEY (`username`) REFERENCES `users` (`username`)
15 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
16 |
17 | -- ----------------------------
18 | -- Records of authorities
19 | -- ----------------------------
20 | begin;
21 | INSERT INTO `authorities` VALUES ('reader', 'READ');
22 | INSERT INTO `authorities` VALUES ('writer', 'READ,WRITE');
23 | COMMIT;
24 |
25 | -- ----------------------------
26 | -- Table structure for oauth_approvals
27 | -- ----------------------------
28 | DROP TABLE IF EXISTS `oauth_approvals`;
29 | create TABLE `oauth_approvals` (
30 | `userId` varchar(256) DEFAULT NULL,
31 | `clientId` varchar(256) DEFAULT NULL,
32 | `partnerKey` varchar(32) DEFAULT NULL,
33 | `scope` varchar(256) DEFAULT NULL,
34 | `status` varchar(10) DEFAULT NULL,
35 | `expiresAt` datetime DEFAULT NULL,
36 | `lastModifiedAt` datetime DEFAULT NULL
37 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
38 |
39 | -- ----------------------------
40 | -- Table structure for oauth_client_details
41 | -- ----------------------------
42 | DROP TABLE IF EXISTS `oauth_client_details`;
43 | create TABLE `oauth_client_details` (
44 | `client_id` varchar(255) NOT NULL,
45 | `resource_ids` varchar(255) DEFAULT NULL,
46 | `client_secret` varchar(255) DEFAULT NULL,
47 | `scope` varchar(255) DEFAULT NULL,
48 | `authorized_grant_types` varchar(255) DEFAULT NULL,
49 | `web_server_redirect_uri` varchar(255) DEFAULT NULL,
50 | `authorities` varchar(255) DEFAULT NULL,
51 | `access_token_validity` int(11) DEFAULT NULL,
52 | `refresh_token_validity` int(11) DEFAULT NULL,
53 | `additional_information` varchar(4096) DEFAULT NULL,
54 | `autoapprove` varchar(255) DEFAULT NULL,
55 | PRIMARY KEY (`client_id`)
56 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
57 |
58 | -- ----------------------------
59 | -- Records of oauth_client_details
60 | -- ----------------------------
61 | BEGIN;
62 | INSERT INTO `oauth_client_details` VALUES ('userservice1', 'userservice', '1234', 'FOO', 'password,refresh_token', '', 'READ,WRITE', 7200, NULL, NULL, 'true');
63 | INSERT INTO `oauth_client_details` VALUES ('userservice2', 'userservice', '1234', 'FOO', 'client_credentials,refresh_token', '', 'READ,WRITE', 7200, NULL, NULL, 'true');
64 | INSERT INTO `oauth_client_details` VALUES ('userservice3', 'userservice', '1234', 'FOO', 'authorization_code,refresh_token', 'https://baidu.com,http://localhost:8082/ui/login,http://localhost:8083/ui/login,http://localhost:8082/ui/remoteCall', 'READ,WRITE', 7200, NULL, NULL, 'false');
65 | COMMIT;
66 |
67 | -- ----------------------------
68 | -- Table structure for oauth_code
69 | -- ----------------------------
70 | DROP TABLE IF EXISTS `oauth_code`;
71 | create TABLE `oauth_code` (
72 | `code` varchar(255) DEFAULT NULL,
73 | `authentication` blob
74 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
75 |
76 | -- ----------------------------
77 | -- Table structure for users
78 | -- ----------------------------
79 | DROP TABLE IF EXISTS `users`;
80 | create TABLE `users` (
81 | `username` varchar(50) NOT NULL,
82 | `password` varchar(100) NOT NULL,
83 | `enabled` tinyint(1) NOT NULL,
84 | PRIMARY KEY (`username`)
85 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
86 |
87 | -- ----------------------------
88 | -- Records of users
89 | -- ----------------------------
90 | BEGIN;
91 | INSERT INTO `users` VALUES ('reader', '$2a$04$C6pPJvC1v6.enW6ZZxX.luTdpSI/1gcgTVN7LhvQV6l/AfmzNU/3i', 1);
92 | INSERT INTO `users` VALUES ('writer', '$2a$04$M9t2oVs3/VIreBMocOujqOaB/oziWL0SnlWdt8hV4YnlhQrORA0fS', 1);
93 | COMMIT;
94 |
95 | SET FOREIGN_KEY_CHECKS = 1;
96 |
--------------------------------------------------------------------------------
/springsecurity101-cloud-oauth2-server/src/main/java/me/josephzhu/springsecurity101/cloud/oauth2/server/OAuth2ServerConfiguration.java:
--------------------------------------------------------------------------------
1 | package me.josephzhu.springsecurity101.cloud.oauth2.server;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 | import org.springframework.core.io.ClassPathResource;
7 | import org.springframework.security.authentication.AuthenticationManager;
8 | import org.springframework.security.crypto.password.NoOpPasswordEncoder;
9 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
10 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
11 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
12 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
13 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
14 | import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
15 | import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
16 | import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices;
17 | import org.springframework.security.oauth2.provider.token.TokenEnhancer;
18 | import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
19 | import org.springframework.security.oauth2.provider.token.TokenStore;
20 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
21 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
22 | import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
23 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
24 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
25 |
26 | import javax.sql.DataSource;
27 | import java.util.Arrays;
28 |
29 | @Configuration
30 | @EnableAuthorizationServer //开启授权服务器
31 | public class OAuth2ServerConfiguration extends AuthorizationServerConfigurerAdapter {
32 | @Autowired
33 | private DataSource dataSource;
34 | @Autowired
35 | private AuthenticationManager authenticationManager;
36 |
37 | /**
38 | * 我们配置了使用数据库来维护客户端信息。虽然在各种Demo中我们经常看到的是在内存中维护客户端信息,通过配置直接写死在这里。
39 | * 但是,对于实际的应用我们一般都会用数据库来维护这个信息,甚至还会建立一套工作流来允许客户端自己申请ClientID。
40 | * @param clients
41 | * @throws Exception
42 | */
43 | @Override
44 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
45 | clients.jdbc(dataSource);
46 | }
47 |
48 | /**
49 | * 这里干了两个事情,首先打开了验证Token的访问权限(以便之后我们演示)。
50 | * 然后允许ClientSecret明文方式保存并且可以通过表单提交(而不仅仅是Basic Auth方式提交),之后会演示到这个。
51 | * @param security
52 | * @throws Exception
53 | */
54 | @Override
55 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
56 | security.checkTokenAccess("permitAll()").allowFormAuthenticationForClients().passwordEncoder(NoOpPasswordEncoder.getInstance());
57 | }
58 |
59 | /**
60 | * 干了几个事情:
61 | * 1、配置我们的Token存放方式不是内存、数据库或Redis方式,而是JWT方式。
62 | * JWT是Json Web Token缩写也就是使用JSON数据格式包装的Token,由.句号把整个JWT分隔为头、数据体、签名三部分。
63 | * JWT保存Token虽然易于使用但是不是那么安全,一般用于内部,并且需要走HTTPS+配置比较短的失效时间。
64 | * 2、配置了JWT Token的非对称加密来进行签名
65 | * 3、配置了一个自定义的Token增强器,把更多信息放入Token中
66 | * 4、配置了使用JDBC数据库方式来保存用户的授权批准记录
67 | * @param endpoints
68 | * @throws Exception
69 | */
70 | @Override
71 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
72 | TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
73 | tokenEnhancerChain.setTokenEnhancers(
74 | Arrays.asList(tokenEnhancer(), jwtTokenEnhancer()));
75 |
76 | endpoints.approvalStore(approvalStore())
77 | .authorizationCodeServices(authorizationCodeServices())
78 | .tokenStore(tokenStore())
79 | .tokenEnhancer(tokenEnhancerChain)
80 | .authenticationManager(authenticationManager);
81 | }
82 |
83 | /**
84 | * 使用JDBC数据库方式来保存授权码
85 | *
86 | * @return
87 | */
88 | @Bean
89 | public AuthorizationCodeServices authorizationCodeServices() {
90 | return new JdbcAuthorizationCodeServices(dataSource);
91 | }
92 |
93 | /**
94 | * 使用JWT令牌存储
95 | * @return
96 | */
97 | @Bean
98 | public TokenStore tokenStore() {
99 | return new JwtTokenStore(jwtTokenEnhancer());
100 | }
101 |
102 | /**
103 | * 使用JDBC数据库方式来保存用户的授权批准记录
104 | * @return
105 | */
106 | @Bean
107 | public JdbcApprovalStore approvalStore() {
108 | return new JdbcApprovalStore(dataSource);
109 | }
110 |
111 | /**
112 | * 自定义的Token增强器,把更多信息放入Token中
113 | * @return
114 | */
115 | @Bean
116 | public TokenEnhancer tokenEnhancer() {
117 | return new CustomTokenEnhancer();
118 | }
119 |
120 | /**
121 | * 配置JWT令牌使用非对称加密方式来验证
122 | * @return
123 | */
124 | @Bean
125 | protected JwtAccessTokenConverter jwtTokenEnhancer() {
126 | KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "mySecretKey".toCharArray());
127 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
128 | converter.setKeyPair(keyStoreKeyFactory.getKeyPair("jwt"));
129 | return converter;
130 | }
131 |
132 | /**
133 | * 配置登录页面的视图信息(其实可以独立一个配置类更规范)
134 | */
135 | @Configuration
136 | static class MvcConfig implements WebMvcConfigurer {
137 | @Override
138 | public void addViewControllers(ViewControllerRegistry registry) {
139 | registry.addViewController("login").setViewName("login");
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------