项目作者: zacscoding

项目描述 :
spring boot oauth2 jdbc server and client examples
高级语言: Java
项目地址: git://github.com/zacscoding/springboot-oauth2-example.git
创建时间: 2019-10-01T07:42:18Z
项目社区:https://github.com/zacscoding/springboot-oauth2-example

开源协议:

下载


Oauth2 server & client with spring boot


Getting started

Git clone

  1. $ git clone https://github.com/zacscoding/springboot-oauth2-example.git
  2. $ cd springboot-oauth2-example

Start OAuth2 server

  1. $ ./gradlew oauth-server:bootRun

And then connect to http://localhost:3000/swagger-ui.html in browser.

Call /accounts/me without access token, then receive unauthorized response.

Sign in by using Authorize tab in swagger-ui and login with below info.


















username admin@email.com
password admin
client_id application
client_secret pass

Then will receive success response after signed in.

Can see full flow (get and refresh token) in tests code


Project structure

  1. springboot-oauth2-example$ tree ./ -L 2
  2. ├── oauth-server <-- oauth2 resource server
  3. ├── build.gradle
  4. └── src

Resource and auth server

Oauth-server is a resource and auth server like facebook, google.

Token info is stored at database given DataSource i.e JdbcTokenStore.

Can see full example of configuration config package.

Configurer server

SecurityConfiguration extended WebSecurityConfigurerAdapter

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.security.authentication.AuthenticationManager;
  4. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  5. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  6. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  7. import org.springframework.security.crypto.password.PasswordEncoder;
  8. import lombok.RequiredArgsConstructor;
  9. import server.account.service.AccountService;
  10. @RequiredArgsConstructor
  11. @Configuration
  12. @EnableWebSecurity
  13. public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
  14. private final AccountService accountService;
  15. private final PasswordEncoder passwordEncoder;
  16. @Bean
  17. @Override
  18. public AuthenticationManager authenticationManagerBean() throws Exception {
  19. return super.authenticationManagerBean();
  20. }
  21. @Override
  22. public void configure(WebSecurity web) throws Exception {
  23. // ignore swagger resources
  24. web.ignoring().antMatchers(
  25. "/v2/api-docs", "/swagger-resources/**",
  26. "/swagger-ui.html", "/webjars/**", "/swagger/**");
  27. }
  28. @Override
  29. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  30. auth.userDetailsService(accountService)
  31. .passwordEncoder(passwordEncoder);
  32. }
  33. }

ResourceServerConfiguration extended ResourceServerConfigurerAdapter

  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.http.HttpMethod;
  3. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  4. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
  5. import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
  6. import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
  7. import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
  8. @Configuration
  9. @EnableResourceServer
  10. public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
  11. @Override
  12. public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  13. resources.resourceId("examples");
  14. }
  15. @Override
  16. public void configure(HttpSecurity http) throws Exception {
  17. http.headers().frameOptions().disable();
  18. http.anonymous()
  19. .and()
  20. .authorizeRequests()
  21. .mvcMatchers(HttpMethod.GET, "/api/hello")
  22. .permitAll()
  23. .anyRequest()
  24. .authenticated()
  25. .and()
  26. .exceptionHandling()
  27. .accessDeniedHandler(new OAuth2AccessDeniedHandler());
  28. }
  29. }

AuthServerConfiguration extended AuthorizationServerConfigurerAdapter

  1. import javax.sql.DataSource;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.security.authentication.AuthenticationManager;
  5. import org.springframework.security.crypto.password.PasswordEncoder;
  6. import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
  7. import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
  8. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
  9. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
  10. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
  11. import org.springframework.security.oauth2.provider.approval.ApprovalStore;
  12. import org.springframework.security.oauth2.provider.approval.JdbcApprovalStore;
  13. import org.springframework.security.oauth2.provider.token.TokenStore;
  14. import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
  15. import lombok.RequiredArgsConstructor;
  16. import server.account.service.AccountService;
  17. @RequiredArgsConstructor
  18. @Configuration
  19. @EnableAuthorizationServer
  20. public class AuthServerConfiguration extends AuthorizationServerConfigurerAdapter {
  21. // required
  22. private final PasswordEncoder passwordEncoder;
  23. private final AuthenticationManager authenticationManager;
  24. private final AccountService accountService;
  25. private final DataSource dataSource;
  26. @Override
  27. public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  28. security.passwordEncoder(passwordEncoder);
  29. }
  30. @Override
  31. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  32. clients.jdbc(dataSource);
  33. }
  34. @Override
  35. public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  36. endpoints.authenticationManager(authenticationManager)
  37. .userDetailsService(accountService)
  38. .tokenStore(tokenStore())
  39. .approvalStore(approvalStore());
  40. }
  41. @Bean
  42. public TokenStore tokenStore() {
  43. return new JdbcTokenStore(dataSource);
  44. }
  45. @Bean
  46. public ApprovalStore approvalStore() {
  47. return new JdbcApprovalStore(dataSource);
  48. }
  49. }

Schema of oauth2

See schema-oauth2-h2.sql.

Test OAuth2

Tests with spring test

See OAuth2ClientIT.

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. @AutoConfigureMockMvc
  4. @ActiveProfiles("test")
  5. public class OAuth2ClientIT {
  6. @Autowired
  7. protected MockMvc mockMvc;
  8. @Autowired
  9. protected ObjectMapper objectMapper;
  10. @Test
  11. public void runOauthClient() throws Exception {
  12. /**
  13. * 1) /accounts/me with anonymous user
  14. * Try to access "/accounts/me" without access token.
  15. * Then receive unauthorized response
  16. */
  17. mockMvc.perform(get("/accounts/me"))
  18. .andDo(print())
  19. .andExpect(status().isUnauthorized());
  20. /**
  21. * 2) getting access token
  22. *
  23. * Try to get access token with BasicAuth.
  24. *
  25. * * Header
  26. * - Key : "Authentication", Value: Base64Enc("application:pass")
  27. *
  28. * * Body with form-data
  29. * - username=user@gmail.com
  30. * - password=user
  31. * - grant_type=password
  32. */
  33. final String username = "user@gmail.com";
  34. final String password = "user";
  35. final String clientId = "application";
  36. final String clientSecret = "pass";
  37. ResultActions perform = mockMvc.perform(post("/oauth/token")
  38. .with(httpBasic(clientId, clientSecret))
  39. .param("username", username)
  40. .param("password", password)
  41. .param("grant_type", "password"));
  42. String response = perform.andReturn().getResponse().getContentAsString();
  43. System.out.println("/oauth/token response : " + response);
  44. Map<String, Object> results = new Jackson2JsonParser().parseMap(response);
  45. String accessToken = results.get("access_token").toString();
  46. String refreshToken = results.get("refresh_token").toString();
  47. String bearerToken = "Bearer " + accessToken;
  48. /**
  49. * 3) request with auth token
  50. * Try to get resource with access token (Bearer)
  51. * * Header
  52. * - Key : "Authentication", Value: Bearer <access-token>
  53. */
  54. mockMvc.perform(get("/accounts/me")
  55. .header(HttpHeaders.AUTHORIZATION, bearerToken))
  56. .andDo(print())
  57. .andExpect(jsonPath("id").exists())
  58. .andExpect(jsonPath("email").value(username))
  59. .andExpect(jsonPath("age").exists());
  60. /**
  61. * 4) refresh token
  62. * Try to get a new access token with refresh token
  63. *
  64. * * Header
  65. * - Key : "Authentication", Value: Base64Enc("application:pass")
  66. *
  67. * * Body with form-data
  68. * - grant_type=refresh_token
  69. * - refresh_token=<refresh-token>
  70. */
  71. perform = mockMvc.perform(post("/oauth/token")
  72. .with(httpBasic(clientId, clientSecret))
  73. .param("grant_type", "refresh_token")
  74. .param("refresh_token", refreshToken));
  75. response = perform.andReturn().getResponse().getContentAsString();
  76. results = new Jackson2JsonParser().parseMap(response);
  77. String updatedAccessToken = results.get("access_token").toString();
  78. String updatedBearerToken = "Bearer " + updatedAccessToken;
  79. assertThat(accessToken).isNotEqualTo(updatedAccessToken);
  80. // failed to request if access with prev token.
  81. mockMvc.perform(get("/accounts/me")
  82. .header(HttpHeaders.AUTHORIZATION, bearerToken))
  83. .andExpect(status().isUnauthorized());
  84. // success to request if access with new token
  85. mockMvc.perform(get("/accounts/me")
  86. .header(HttpHeaders.AUTHORIZATION, updatedBearerToken))
  87. .andDo(print())
  88. .andExpect(jsonPath("id").exists())
  89. .andExpect(jsonPath("email").value(username))
  90. .andExpect(jsonPath("age").exists());
  91. }
  92. }

Oauth2 client