├── README.md
├── authorization-server
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── cn
│ │ │ └── merryyou
│ │ │ └── security
│ │ │ ├── SpringBoot2Oauth2Application.java
│ │ │ ├── config
│ │ │ └── TokenStoreConfig.java
│ │ │ ├── handler
│ │ │ └── AppLoginInSuccessHandler.java
│ │ │ ├── properties
│ │ │ ├── OAuth2ClientProperties.java
│ │ │ ├── OAuth2CoreConfig.java
│ │ │ └── OAuth2Properties.java
│ │ │ ├── security
│ │ │ ├── MyUserDetailsService.java
│ │ │ ├── SecurityConfig.java
│ │ │ └── jwt
│ │ │ │ └── MerryyouJwtTokenEnhancer.java
│ │ │ ├── server
│ │ │ ├── MerryyouAuthorizationServerConfig.java
│ │ │ └── MerryyouResourceServerConfig.java
│ │ │ └── utils
│ │ │ └── JsonUtil.java
│ └── resources
│ │ └── application.yml
│ └── test
│ └── java
│ └── cn
│ └── merryyou
│ └── security
│ └── SpringBoot2Oauth2Test.java
├── pom.xml
└── resource-server
├── pom.xml
├── resource-server.iml
└── src
└── main
├── java
└── cn
│ └── merryyou
│ └── security
│ ├── SpringBoot2Oauth2ResourceApplication.java
│ └── resource
│ └── MerryyouResourceServerConfiguration.java
└── resources
└── application.yml
/README.md:
--------------------------------------------------------------------------------
1 | # springboot2.0-oauth2
2 | [](https://github.com/longfeizheng/springboot2.0-oauth2/stargazers)
3 | [](https://github.com/longfeizheng/springboot2.0-oauth2/fork)
4 | [](https://github.com/longfeizheng/springboot2.0-oauth2/watchers)
5 | - [springboot 2.0 整合Oauth2](https://longfeizheng.github.io/2018/04/29/Spring-Boot-2.0-%E6%95%B4%E5%90%88-Spring-Security-Oauth2/)
6 | - [SpringBott 1.5.6.RELEASE整合Oauth2](https://github.com/longfeizheng/security-oauth2)
7 |
8 |
9 | #### 授权码模式
10 |
11 | [](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth202.gif "https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth202.gif")
12 |
13 | #### 密码模式
14 |
15 | [](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth203.gif "https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth203.gif")
16 |
17 | #### 自定义登录
18 |
19 | [](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth204.gif "https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth204.gif")
20 |
21 | #### 刷新token
22 |
23 | [](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth205.gif "https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth205.gif")
24 |
25 | #### 测试资源服务器
26 |
27 | [](https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth206.gif "https://raw.githubusercontent.com/longfeizheng/longfeizheng.github.io/master/images/security/spring-security-oauth206.gif")
28 |
--------------------------------------------------------------------------------
/authorization-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot2.0-oauth2
7 | cn.merryyou
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | authorization-server
13 |
14 |
15 |
16 | UTF-8
17 | UTF-8
18 | 1.8
19 |
20 |
21 |
22 |
23 | org.springframework.cloud
24 | spring-cloud-starter-oauth2
25 |
26 |
27 |
28 | org.springframework.security
29 | spring-security-jwt
30 |
31 |
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-test
36 |
37 |
38 |
39 | org.springframework.boot
40 | spring-boot-starter-redis
41 | 1.4.7.RELEASE
42 |
43 |
44 |
45 | org.projectlombok
46 | lombok
47 | 1.16.14
48 |
49 |
50 |
51 | com.google.code.gson
52 | gson
53 | 2.8.2
54 |
55 |
56 |
57 | io.jsonwebtoken
58 | jjwt
59 | 0.9.0
60 |
61 |
62 |
63 | commons-lang
64 | commons-lang
65 | 2.6
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | org.springframework.boot
74 | spring-boot-maven-plugin
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/SpringBoot2Oauth2Application.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security;
2 |
3 | import cn.merryyou.security.properties.OAuth2Properties;
4 | import cn.merryyou.security.utils.JsonUtil;
5 | import io.jsonwebtoken.Claims;
6 | import io.jsonwebtoken.Jwts;
7 | import lombok.extern.slf4j.Slf4j;
8 | import org.apache.commons.lang.StringUtils;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.SpringApplication;
11 | import org.springframework.boot.autoconfigure.SpringBootApplication;
12 | import org.springframework.security.core.Authentication;
13 | import org.springframework.web.bind.annotation.GetMapping;
14 | import org.springframework.web.bind.annotation.RestController;
15 |
16 | import javax.servlet.http.HttpServletRequest;
17 | import java.io.UnsupportedEncodingException;
18 | import java.security.Principal;
19 |
20 | /**
21 | * Created on 2018/4/28.
22 | *
23 | * @author zlf
24 | * @since 1.0
25 | */
26 | @RestController
27 | @SpringBootApplication
28 | @Slf4j
29 | public class SpringBoot2Oauth2Application {
30 |
31 | @Autowired
32 | private OAuth2Properties oAuth2Properties;
33 |
34 |
35 | public static void main(String[] args) {
36 | SpringApplication.run(SpringBoot2Oauth2Application.class, args);
37 | }
38 |
39 | @GetMapping("/userJwt")
40 | public Object getCurrentUserJwt(Authentication authentication, HttpServletRequest request) throws UnsupportedEncodingException {
41 | log.info("【SecurityOauth2Application】 getCurrentUserJwt authentication={}", JsonUtil.toJson(authentication));
42 |
43 | String header = request.getHeader("Authorization");
44 | String token = StringUtils.substringAfter(header, "bearer ");
45 |
46 | Claims claims = Jwts.parser().setSigningKey(oAuth2Properties.getJwtSigningKey().getBytes("UTF-8")).parseClaimsJws(token).getBody();
47 | String blog = (String) claims.get("blog");
48 | log.info("【SecurityOauth2Application】 getCurrentUser1 blog={}", blog);
49 |
50 | return authentication;
51 | }
52 |
53 | @GetMapping("/userRedis")
54 | public Object getCurrentUserRedis(Authentication authentication) {
55 | log.info("【SecurityOauth2Application】 getCurrentUserRedis authentication={}", JsonUtil.toJson(authentication));
56 |
57 |
58 | return authentication;
59 | }
60 |
61 | @GetMapping("/user/me")
62 | public Principal user(Principal user){
63 | return user;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/config/TokenStoreConfig.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.config;
2 |
3 | import cn.merryyou.security.properties.OAuth2Properties;
4 | import cn.merryyou.security.security.jwt.MerryyouJwtTokenEnhancer;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.data.redis.connection.RedisConnectionFactory;
11 | import org.springframework.security.oauth2.provider.token.TokenEnhancer;
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.security.oauth2.provider.token.store.redis.RedisTokenStore;
16 |
17 | /**
18 | * Created on 2018/1/21 0021.
19 | *
20 | * @author zlf
21 | * @email i@merryyou.cn
22 | * @since 1.0
23 | */
24 | @Configuration
25 | public class TokenStoreConfig {
26 | /**
27 | * redis连接工厂
28 | */
29 | @Autowired
30 | private RedisConnectionFactory redisConnectionFactory;
31 |
32 |
33 | /**
34 | * 用于存放token
35 | * @return
36 | */
37 | @Bean
38 | @ConditionalOnProperty(prefix = "merryyou.security.oauth2", name = "storeType", havingValue = "redis")
39 | public TokenStore redisTokenStore() {
40 | return new RedisTokenStore(redisConnectionFactory);
41 | }
42 |
43 | /**
44 | * jwt TOKEN配置信息
45 | */
46 | @Configuration
47 | @ConditionalOnProperty(prefix = "merryyou.security.oauth2", name = "storeType", havingValue = "jwt", matchIfMissing = true)
48 | public static class JwtTokenCofnig{
49 |
50 | @Autowired
51 | private OAuth2Properties oAuth2Properties;
52 |
53 | /**
54 | * 使用jwtTokenStore存储token
55 | * @return
56 | */
57 | @Bean
58 | public TokenStore jwtTokenStore(){
59 | return new JwtTokenStore(jwtAccessTokenConverter());
60 | }
61 |
62 | /**
63 | * 用于生成jwt
64 | * @return
65 | */
66 | @Bean
67 | public JwtAccessTokenConverter jwtAccessTokenConverter(){
68 | JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
69 | accessTokenConverter.setSigningKey(oAuth2Properties.getJwtSigningKey());//生成签名的key
70 | return accessTokenConverter;
71 | }
72 |
73 | /**
74 | * 用于扩展JWT
75 | * @return
76 | */
77 | @Bean
78 | @ConditionalOnMissingBean(name = "jwtTokenEnhancer")
79 | public TokenEnhancer jwtTokenEnhancer(){
80 | return new MerryyouJwtTokenEnhancer();
81 | }
82 |
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/handler/AppLoginInSuccessHandler.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.handler;
2 |
3 | import cn.merryyou.security.utils.JsonUtil;
4 | import com.fasterxml.jackson.databind.ObjectMapper;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.security.authentication.BadCredentialsException;
8 | import org.springframework.security.core.Authentication;
9 | import org.springframework.security.crypto.codec.Base64;
10 | import org.springframework.security.crypto.password.PasswordEncoder;
11 | import org.springframework.security.oauth2.common.OAuth2AccessToken;
12 | import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
13 | import org.springframework.security.oauth2.provider.*;
14 | import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
15 | import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
16 | import org.springframework.stereotype.Component;
17 |
18 | import javax.servlet.ServletException;
19 | import javax.servlet.http.HttpServletRequest;
20 | import javax.servlet.http.HttpServletResponse;
21 | import java.io.IOException;
22 | import java.util.HashMap;
23 |
24 | /**
25 | * APP登录成功处理器
26 | * Created on 2018/1/21 0021.
27 | *
28 | * @author zlf
29 | * @email i@merryyou.cn
30 | * @since 1.0
31 | */
32 |
33 | @Slf4j
34 | @Component("appLoginInSuccessHandler")
35 | public class AppLoginInSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
36 |
37 | @Autowired
38 | private ObjectMapper objectMapper;
39 |
40 | @Autowired
41 | private PasswordEncoder passwordEncoder;
42 |
43 | @Autowired
44 | private ClientDetailsService clientDetailsService;
45 |
46 | @Autowired
47 | private AuthorizationServerTokenServices authorizationServerTokenServices;
48 |
49 | @Override
50 | public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
51 |
52 | log.info("【AppLoginInSuccessHandler】 onAuthenticationSuccess authentication={}", authentication);
53 |
54 | String header = request.getHeader("Authorization");
55 |
56 | if (header == null || !header.startsWith("Basic ")) {
57 | throw new UnapprovedClientAuthenticationException("请求头中无client信息");
58 | }
59 | String[] tokens = this.extractAndDecodeHeader(header, request);
60 |
61 | assert tokens.length == 2;
62 |
63 | String clientId = tokens[0];
64 | String clientSecret = tokens[1];
65 |
66 | ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);
67 |
68 | if (clientDetails == null) {
69 | throw new UnapprovedClientAuthenticationException("clientId 对应的配置信息不存在" + clientId);
70 | } else if (!passwordEncoder.matches(clientSecret, clientDetails.getClientSecret())) {
71 | throw new UnapprovedClientAuthenticationException("clientSecret 不匹配" + clientId);
72 | }
73 |
74 | TokenRequest tokenRequest = new TokenRequest(new HashMap<>(), clientId, clientDetails.getScope(), "custom");
75 |
76 | OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
77 |
78 | OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
79 |
80 | OAuth2AccessToken token = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
81 |
82 | response.setContentType("application/json;charset=UTF-8");
83 | response.getWriter().write(objectMapper.writeValueAsString(token));
84 | log.info("token={}", JsonUtil.toJson(token));
85 |
86 | }
87 |
88 | /**
89 | * 解码
90 | *
91 | * @param header
92 | * @param request
93 | * @return
94 | * @throws IOException
95 | */
96 | private String[] extractAndDecodeHeader(String header, HttpServletRequest request) throws IOException {
97 | byte[] base64Token = header.substring(6).getBytes("UTF-8");
98 |
99 | byte[] decoded;
100 | try {
101 | decoded = Base64.decode(base64Token);
102 | } catch (IllegalArgumentException var7) {
103 | throw new BadCredentialsException("Failed to decode basic authentication token");
104 | }
105 |
106 | String token = new String(decoded, "UTF-8");
107 | int delim = token.indexOf(":");
108 | if (delim == -1) {
109 | throw new BadCredentialsException("Invalid basic authentication token");
110 | } else {
111 | return new String[]{token.substring(0, delim), token.substring(delim + 1)};
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/properties/OAuth2ClientProperties.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.properties;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * Created on 2018/1/24 0024.
7 | *
8 | * @author zlf
9 | * @email i@merryyou.cn
10 | * @since 1.0
11 | */
12 | @Data
13 | public class OAuth2ClientProperties {
14 |
15 | private String clientId;
16 |
17 | private String clientSecret;
18 |
19 | private Integer accessTokenValiditySeconds = 7200;
20 | }
21 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/properties/OAuth2CoreConfig.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.properties;
2 |
3 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | /**
7 | * Created on 2018/1/24 0024.
8 | *
9 | * @author zlf
10 | * @email i@merryyou.cn
11 | * @since 1.0
12 | */
13 | @Configuration
14 | @EnableConfigurationProperties(OAuth2Properties.class)
15 | public class OAuth2CoreConfig {
16 | }
17 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/properties/OAuth2Properties.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.properties;
2 |
3 | import lombok.Data;
4 | import org.springframework.boot.context.properties.ConfigurationProperties;
5 |
6 | /**
7 | * Created on 2018/1/24 0024.
8 | *
9 | * @author zlf
10 | * @email i@merryyou.cn
11 | * @since 1.0
12 | */
13 | @Data
14 | @ConfigurationProperties(prefix = "merryyou.security.oauth2")
15 | public class OAuth2Properties {
16 |
17 | private String jwtSigningKey = "merryyou";
18 |
19 | private OAuth2ClientProperties[] clients = {};
20 | }
21 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/security/MyUserDetailsService.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.security;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.security.core.authority.AuthorityUtils;
5 | import org.springframework.security.core.userdetails.User;
6 | import org.springframework.security.core.userdetails.UserDetails;
7 | import org.springframework.security.core.userdetails.UserDetailsService;
8 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
9 | import org.springframework.security.crypto.password.PasswordEncoder;
10 | import org.springframework.stereotype.Component;
11 |
12 | /**
13 | * Created on 2018/1/17.
14 | *
15 | * @author zlf
16 | * @since 1.0
17 | */
18 | @Component
19 | public class MyUserDetailsService implements UserDetailsService {
20 |
21 | @Autowired
22 | private PasswordEncoder passwordEncoder;
23 |
24 | @Override
25 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
26 | return new User(username, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/security/SecurityConfig.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.security;//package cn.merryyou.security.security;
2 |
3 |
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.web.builders.HttpSecurity;
8 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
9 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 | import org.springframework.security.crypto.password.PasswordEncoder;
11 |
12 | /**
13 | * Created on 2018/1/19.
14 | *
15 | * @author zlf
16 | * @since 1.0
17 | */
18 | @Configuration
19 | public class SecurityConfig extends WebSecurityConfigurerAdapter {
20 |
21 | @Bean
22 | @Override
23 | public AuthenticationManager authenticationManagerBean() throws Exception {
24 | AuthenticationManager manager = super.authenticationManagerBean();
25 | return manager;
26 | }
27 |
28 | @Bean
29 | public PasswordEncoder passwordEncoder() {
30 | return new BCryptPasswordEncoder();
31 | }
32 |
33 | @Override
34 | protected void configure(HttpSecurity http) throws Exception {
35 | http
36 | // .formLogin().and()
37 | .httpBasic().and()
38 | .csrf().disable();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/security/jwt/MerryyouJwtTokenEnhancer.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.security.jwt;
2 |
3 | import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
4 | import org.springframework.security.oauth2.common.OAuth2AccessToken;
5 | import org.springframework.security.oauth2.provider.OAuth2Authentication;
6 | import org.springframework.security.oauth2.provider.token.TokenEnhancer;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | /**
12 | * Created on 2018/1/21 0021.
13 | *
14 | * @author zlf
15 | * @email i@merryyou.cn
16 | * @since 1.0
17 | */
18 | public class MerryyouJwtTokenEnhancer implements TokenEnhancer {
19 | @Override
20 | public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
21 | Map info = new HashMap<>();
22 | info.put("blog", "https://longfeizheng.github.io/");
23 | ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(info);
24 | return accessToken;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/server/MerryyouAuthorizationServerConfig.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.server;
2 |
3 | import cn.merryyou.security.properties.OAuth2ClientProperties;
4 | import cn.merryyou.security.properties.OAuth2Properties;
5 | import org.apache.commons.lang.ArrayUtils;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.security.authentication.AuthenticationManager;
9 | import org.springframework.security.core.userdetails.UserDetailsService;
10 | import org.springframework.security.crypto.password.PasswordEncoder;
11 | import org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder;
12 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
13 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
14 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
15 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
16 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
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 |
22 | import java.util.ArrayList;
23 | import java.util.List;
24 |
25 | /**
26 | * Created on 2018/1/15 0015.
27 | *
28 | * @author zlf
29 | * @email i@merryyou.cn
30 | * @since 1.0
31 | */
32 | @Configuration
33 | @EnableAuthorizationServer
34 | public class MerryyouAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
35 |
36 | @Autowired
37 | private OAuth2Properties oAuth2Properties;
38 |
39 | @Autowired
40 | private AuthenticationManager authenticationManager;
41 |
42 | @Autowired
43 | private UserDetailsService userDetailsService;
44 |
45 | @Autowired
46 | private TokenStore tokenStore;
47 |
48 | @Autowired(required = false)
49 | private JwtAccessTokenConverter jwtAccessTokenConverter;
50 |
51 | @Autowired(required = false)
52 | private TokenEnhancer jwtTokenEnhancer;
53 |
54 | @Autowired
55 | private PasswordEncoder passwordEncoder;
56 |
57 | @Override
58 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
59 | endpoints.tokenStore(tokenStore)
60 | .authenticationManager(authenticationManager)
61 | .userDetailsService(userDetailsService);
62 | //扩展token返回结果
63 | if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
64 | TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
65 | List enhancerList = new ArrayList();
66 | enhancerList.add(jwtTokenEnhancer);
67 | enhancerList.add(jwtAccessTokenConverter);
68 | tokenEnhancerChain.setTokenEnhancers(enhancerList);
69 | //jwt
70 | endpoints.tokenEnhancer(tokenEnhancerChain)
71 | .accessTokenConverter(jwtAccessTokenConverter);
72 | }
73 | }
74 |
75 | /**
76 | * 配置客户端一些信息
77 | *
78 | * @param clients
79 | * @throws Exception
80 | */
81 | @Override
82 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
83 | InMemoryClientDetailsServiceBuilder build = clients.inMemory();
84 | if (ArrayUtils.isNotEmpty(oAuth2Properties.getClients())) {
85 | for (OAuth2ClientProperties config : oAuth2Properties.getClients()) {
86 | build.withClient(config.getClientId())
87 | .secret(passwordEncoder.encode(config.getClientSecret()))
88 | .accessTokenValiditySeconds(config.getAccessTokenValiditySeconds())
89 | .refreshTokenValiditySeconds(60 * 60 * 24 * 15)
90 | .authorizedGrantTypes("refresh_token", "password", "authorization_code")//OAuth2支持的验证模式
91 | .redirectUris("http://www.merryyou.cn")
92 | .scopes("all");
93 | }
94 | }
95 | }
96 |
97 | // @Override
98 | // public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
99 | // //允许表单认证
100 | // oauthServer.allowFormAuthenticationForClients();
101 | // oauthServer.passwordEncoder(passwordEncoder);
102 | // }
103 |
104 | /**
105 | * springSecurity 授权表达式,
106 | * @param security
107 | * @throws Exception
108 | */
109 | @Override
110 | public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
111 | security.tokenKeyAccess("permitAll()");
112 | security.checkTokenAccess("isAuthenticated()");
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/server/MerryyouResourceServerConfig.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.server;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
7 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
8 | import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
9 |
10 | /**
11 | * Created on 2018/1/17.
12 | *
13 | * @author zlf
14 | * @since 1.0
15 | */
16 | @Configuration
17 | @EnableResourceServer
18 | public class MerryyouResourceServerConfig extends ResourceServerConfigurerAdapter {
19 |
20 | /**
21 | * 自定义登录成功处理器
22 | */
23 | @Autowired
24 | private AuthenticationSuccessHandler appLoginInSuccessHandler;
25 |
26 | @Override
27 | public void configure(HttpSecurity http) throws Exception {
28 | http.formLogin()
29 | .successHandler(appLoginInSuccessHandler)//登录成功处理器
30 | .and()
31 | .authorizeRequests().anyRequest().authenticated().and()
32 | .csrf().disable();
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/authorization-server/src/main/java/cn/merryyou/security/utils/JsonUtil.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.utils;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 |
6 | /**
7 | * Created on 2018/1/17.
8 | *
9 | * @author zlf
10 | * @since 1.0
11 | */
12 | public class JsonUtil {
13 | public static String toJson(Object object){
14 | GsonBuilder gsonBuilder = new GsonBuilder();
15 | gsonBuilder.setPrettyPrinting();
16 | Gson gson = gsonBuilder.create();
17 | return gson.toJson(object);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/authorization-server/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8888
3 | spring:
4 | redis:
5 | host: localhost
6 | port: 6379
7 | jedis:
8 | pool:
9 | max-active: 8
10 | max-wait: -1s
11 | min-idle: 0
12 | max-idle: 8
13 | logging:
14 | level:
15 | org.springframework: debug
16 | merryyou:
17 | security:
18 | oauth2:
19 | storeType: jwt #或者jwt
20 | jwtSigningKey: merryyou
21 | clients[0]:
22 | clientId: merryyou
23 | clientSecret: merryyou
24 | clients[1]:
25 | clientId: merryyou1
26 | clientSecret: merryyou1
27 |
--------------------------------------------------------------------------------
/authorization-server/src/test/java/cn/merryyou/security/SpringBoot2Oauth2Test.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security;
2 |
3 | import cn.merryyou.security.utils.JsonUtil;
4 | import lombok.extern.slf4j.Slf4j;
5 | import org.apache.commons.codec.binary.Base64;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.http.*;
10 | import org.springframework.security.oauth2.common.OAuth2AccessToken;
11 | import org.springframework.test.context.junit4.SpringRunner;
12 | import org.springframework.util.LinkedMultiValueMap;
13 | import org.springframework.util.MultiValueMap;
14 | import org.springframework.web.client.RestTemplate;
15 |
16 | /**
17 | * Created on 2018/4/28.
18 | *
19 | * @author zlf
20 | * @since 1.0
21 | */
22 | @RunWith(SpringRunner.class)
23 | @SpringBootTest
24 | @Slf4j
25 | public class SpringBoot2Oauth2Test {
26 | //端口
27 | final static long PORT = 8888;
28 | //clientId
29 | final static String CLIENT_ID = "merryyou";
30 | //clientSecret
31 | final static String CLIENT_SECRET = "merryyou";
32 | //用户名
33 | final static String USERNAME = "admin";
34 | //密码
35 | final static String PASSWORD = "123456";
36 | //获取accessToken得URI
37 | final static String TOKEN_REQUEST_URI = "http://127.0.0.1:" + PORT + "/oauth/token?grant_type=password&username=" + USERNAME + "&password=" + PASSWORD + "&scope=all";
38 | //获取用户信息得URL
39 | final static String USER_INFO_URI = "http://127.0.0.1:" + PORT + "/userRedis";
40 | //登录地址
41 | final static String SIGN_IN_URI = "http://127.0.0.1:" + PORT + "/login";
42 |
43 | @Test
44 | public void getUserInfo() throws Exception {
45 | RestTemplate rest = new RestTemplate();
46 | HttpHeaders headers = new HttpHeaders();
47 | headers.add("authorization", "bearer " + getAccessToken());
48 | HttpEntity entity = new HttpEntity(null, headers);
49 | // pay attention, if using get with headers, should use exchange instead of getForEntity / getForObject
50 | ResponseEntity result = rest.exchange(USER_INFO_URI, HttpMethod.GET, entity, String.class, new Object[]{null});
51 | log.info("用户信息返回的结果={}", JsonUtil.toJson(result));
52 | }
53 |
54 | /**
55 | * 用户名密码登录
56 | * @throws Exception
57 | */
58 | @Test
59 | public void signInTest() throws Exception {
60 | RestTemplate rest = new RestTemplate();
61 | HttpHeaders headers = new HttpHeaders();
62 | headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
63 | headers.add("authorization", getBasicAuthHeader());
64 |
65 | MultiValueMap params = new LinkedMultiValueMap<>();
66 | params.add("username", "admin");
67 | params.add("password", "123456");
68 |
69 | HttpEntity> entity = new HttpEntity(params, headers);
70 | // pay attention, if using get with headers, should use exchange instead of getForEntity / getForObject
71 | ResponseEntity result = rest.exchange(SIGN_IN_URI, HttpMethod.POST, entity, String.class, new Object[]{null});
72 | log.info("登录信息返回的结果={}", JsonUtil.toJson(result));
73 | }
74 |
75 | /**
76 | * 获取accessToken
77 | *
78 | * @return
79 | */
80 | private String getAccessToken() {
81 | RestTemplate rest = new RestTemplate();
82 | HttpHeaders headers = new HttpHeaders();
83 | headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
84 | headers.add("authorization", getBasicAuthHeader());
85 | HttpEntity entity = new HttpEntity(null, headers);
86 | ResponseEntity resp = rest.postForEntity(TOKEN_REQUEST_URI, entity, OAuth2AccessToken.class);
87 | if (!resp.getStatusCode().equals(HttpStatus.OK)) {
88 | throw new RuntimeException(resp.toString());
89 | }
90 | OAuth2AccessToken t = resp.getBody();
91 | log.info("accessToken={}", JsonUtil.toJson(t));
92 | log.info("the response, access_token: " + t.getValue() + "; token_type: " + t.getTokenType() + "; "
93 | + "refresh_token: " + t.getRefreshToken() + "; expiration: " + t.getExpiresIn() + ", expired when:" + t.getExpiration());
94 | return t.getValue();
95 |
96 | }
97 |
98 | /**
99 | * 构建header
100 | *
101 | * @return
102 | */
103 | private String getBasicAuthHeader() {
104 | String auth = CLIENT_ID + ":" + CLIENT_SECRET;
105 | byte[] encodedAuth = Base64.encodeBase64(auth.getBytes());
106 | String authHeader = "Basic " + new String(encodedAuth);
107 | return authHeader;
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | cn.merryyou
8 | springboot2.0-oauth2
9 | pom
10 | 1.0-SNAPSHOT
11 |
12 | authorization-server
13 | resource-server
14 |
15 |
16 |
17 |
18 |
19 | io.spring.platform
20 | platform-bom
21 | Cairo-RELEASE
22 | pom
23 | import
24 |
25 |
26 | org.springframework.cloud
27 | spring-cloud-dependencies
28 | Finchley.RC1
29 | pom
30 | import
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | org.apache.maven.plugins
39 | maven-compiler-plugin
40 | 2.3.2
41 |
42 | 1.8
43 | 1.8
44 | UTF-8
45 |
46 |
47 |
48 |
49 | org.springframework.boot
50 | spring-boot-maven-plugin
51 |
52 |
53 |
54 | repackage
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | spring-snapshots
65 | Spring Snapshots
66 | https://repo.spring.io/snapshot
67 |
68 | true
69 |
70 |
71 |
72 | spring-milestones
73 | Spring Milestones
74 | https://repo.spring.io/milestone
75 |
76 | false
77 |
78 |
79 |
80 |
81 |
82 |
83 | spring-snapshots
84 | Spring Snapshots
85 | https://repo.spring.io/snapshot
86 |
87 | true
88 |
89 |
90 |
91 | spring-milestones
92 | Spring Milestones
93 | https://repo.spring.io/milestone
94 |
95 | false
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/resource-server/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | springboot2.0-oauth2
7 | cn.merryyou
8 | 1.0-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | resource-server
13 |
14 |
15 |
16 | org.springframework.cloud
17 | spring-cloud-starter-oauth2
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/resource-server/resource-server.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/resource-server/src/main/java/cn/merryyou/security/SpringBoot2Oauth2ResourceApplication.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.security.access.prepost.PreAuthorize;
6 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
7 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | /**
12 | * Created on 2018/5/3 0003.
13 | *
14 | * @author zlf
15 | * @email i@merryyou.cn
16 | * @since 1.0
17 | */
18 | @SpringBootApplication
19 | @RestController
20 | @EnableGlobalMethodSecurity(prePostEnabled = true)//开启注解
21 | public class SpringBoot2Oauth2ResourceApplication extends ResourceServerConfigurerAdapter {
22 |
23 | public static void main(String[] args) {
24 | SpringApplication.run(SpringBoot2Oauth2ResourceApplication.class, args);
25 | }
26 |
27 | @RequestMapping(value = "/api")
28 | @PreAuthorize("hasRole('ROLE_USER')")
29 | public String success() {
30 | return "SUCCESS";
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/resource-server/src/main/java/cn/merryyou/security/resource/MerryyouResourceServerConfiguration.java:
--------------------------------------------------------------------------------
1 | package cn.merryyou.security.resource;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.http.HttpMethod;
5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
7 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
8 |
9 | /**
10 | * Created on 2018/5/5 0005.
11 | *
12 | * @author zlf
13 | * @email i@merryyou.cn
14 | * @since 1.0
15 | */
16 | @Configuration
17 | @EnableResourceServer
18 | public class MerryyouResourceServerConfiguration extends ResourceServerConfigurerAdapter {
19 |
20 |
21 | @Override
22 | public void configure(HttpSecurity http) throws Exception {
23 | http.csrf().disable().authorizeRequests().antMatchers("/**").authenticated().antMatchers(HttpMethod.GET, "/api")
24 | // 拦截用户,必须具有所列权限
25 | .hasAuthority("ROLE_USER");
26 | }
27 |
28 |
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/resource-server/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | auth-server: http://localhost:8888 # sso-server地址
2 | server:
3 | port: 8889
4 | security:
5 | oauth2:
6 | client:
7 | client-id: merryyou
8 | client-secret: merryyou
9 | user-authorization-uri: ${auth-server}/oauth/authorize #请求认证的地址
10 | access-token-uri: ${auth-server}/oauth/token #请求令牌的地址
11 | resource:
12 | jwt:
13 | key-uri: ${auth-server}/oauth/token_key
14 | user-info-uri: ${auth-server}/user/me
15 | token-info-uri: ${auth-server}/oauth/check_token
16 | logging:
17 | level:
18 | org.springframework: debug
--------------------------------------------------------------------------------