client_credentials
一、建立應用資源java
@SpringBootApplication public class ClientOAuth2Application { public static void main(String[] args) { SpringApplication.run(ClientOAuth2Application.class, args); } @RestController @RequestMapping("/api") class DemoController { // 能夠匿名訪問 @GetMapping("/public/{id}") public String publicResource(@PathVariable long id) { return "this is public "+id; } // 必須通過認證 @GetMapping("/protect/{id}") public String protectResource(@PathVariable long id) { return "this is protect "+id; } } }
二、配置認證服務器spring
//提供/oauth/authorize,/oauth/token,/oauth/check_token,/oauth/confirm_access,/oauth/error @Configuration @EnableAuthorizationServer public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer .tokenKeyAccess("permitAll()") //allow check token .checkTokenAccess("isAuthenticated()") .allowFormAuthenticationForClients(); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("demoApp") .secret(passwordEncoder().encode("demoAppSecret")) .authorizedGrantTypes("client_credentials", "password", "refresh_token") .scopes("all") .resourceIds("oauth2-resource") .accessTokenValiditySeconds(1200) .refreshTokenValiditySeconds(50000); } }
三、配置資源訪問控制shell
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { /** * 配置資源訪問控制 */ @Override public void configure(HttpSecurity http) throws Exception { http .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .and() .requestMatchers().anyRequest() .and() .anonymous() .and() .authorizeRequests() .antMatchers("/api/public/**").permitAll() .antMatchers("/api/protect/**").access("#oauth2.hasScope('all')") .anyRequest().authenticated(); } }
四、驗證json
一、啓動應用,訪問資源:api
zuizuideMacBook-Pro:~ zuizui$ curl -i http://localhost:8080/api/public/1 HTTP/1.1 200 X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY Content-Type: text/plain;charset=UTF-8 Content-Length: 16 Date: Sun, 05 May 2019 05:40:52 GMT this is public 1
zuizuideMacBook-Pro:~ zuizui$ curl -i http://localhost:8080/api/protect/1 HTTP/1.1 401 Set-Cookie: JSESSIONID=3F3B351204A64E7788A2D988F6F9C53D; Path=/; HttpOnly Cache-Control: no-store Pragma: no-cache WWW-Authenticate: Bearer realm="oauth2-resource", error="unauthorized", error_description="Full authentication is required to access this resource" X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block X-Frame-Options: DENY Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 05 May 2019 05:41:29 GMT {"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
二、獲取token服務器
zuizuideMacBook-Pro:~ zuizui$ curl -i demoApp:demoAppSecret@localhost:8080/oauth/token -d grant_type=client_credentials HTTP/1.1 200 Cache-Control: no-store Pragma: no-cache X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block X-Frame-Options: DENY Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 05 May 2019 05:43:40 GMT {"access_token":"2c24ea79-5e80-43a8-844f-458193ce3173","token_type":"bearer","expires_in":1199,"scope":"all"}
三、攜帶token訪問資源session
zuizuideMacBook-Pro:~ zuizui$ curl -i -H "Authorization:Bearer 2c24ea79-5e80-43a8-844f-458193ce3173" localhost:8080/api/protect/1 HTTP/1.1 200 Set-Cookie: JSESSIONID=F3208F6C579CF2F0456F52D070C34B59; Path=/; HttpOnly X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY Content-Type: text/plain;charset=UTF-8 Content-Length: 17 Date: Sun, 05 May 2019 05:45:32 GMT this is protect 1
resource owner password credentials
密碼模式須要配置
UserDetailsService
和AuthenticationManager
app
<dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
一、準備資源curl
@SpringBootApplication public class OAuth2PasswordCredentialsApplication { public static void main(String[] args) { SpringApplication.run(OAuth2PasswordCredentialsApplication.class, args); } @RestController @RequestMapping("/api") class DemoController { @GetMapping("/public/{id}") public String publicResource(@PathVariable long id) { return "this is public "+id; } @GetMapping("/protect/{id}") public String protectResource(@PathVariable long id) { return "this is protect "+id; } } }
二、認證服務器配置ide
@Configuration @EnableAuthorizationServer public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter { @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer .tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()") .allowFormAuthenticationForClients(); } /** * 注入authenticationManager * 來支持 password grant type */ @Resource private AuthenticationManager authenticationManager; @Resource private PasswordEncoder passwordEncoder; @Bean public InMemoryTokenStore tokenStore() { return new InMemoryTokenStore(); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .authenticationManager(authenticationManager) .tokenStore(tokenStore()); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("demoApp") .secret(passwordEncoder.encode("demoAppSecret")) .authorizedGrantTypes("client_credentials", "password", "refresh_token") .scopes("all") .resourceIds("oauth2-resource") .accessTokenValiditySeconds(1200) .refreshTokenValiditySeconds(50000); } }
三、資源服務器配置
@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter { /** * 要正常運行,須要反註釋掉這段,具體緣由見下面分析 * 這裏設置須要token驗證的url * 這些須要在WebSecurityConfigurerAdapter中排查掉 * 不然優先進入WebSecurityConfigurerAdapter,進行的是basic auth或表單認證,而不是token認證 */ @Override public void configure(HttpSecurity http) throws Exception { http.requestMatchers().antMatchers("/api/**") .and() .authorizeRequests() .antMatchers("/api/**").authenticated(); } public static void main(String[] args) { String encode = Base64.getEncoder().encodeToString("demoApp:demoAppSecret".getBytes()); System.out.println(encode); } }
四、WebSecurity配置
@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.requestMatchers().antMatchers("/oauth/**") .and() .authorizeRequests() .antMatchers("/oauth/**").authenticated(); } //配置內存模式的用戶 @Bean @Override protected UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("demoUser1").password(passwordEncoder() .encode("123456")).authorities("USER").build()); manager.createUser(User.withUsername("demoUser2").password(passwordEncoder() .encode("123456")).authorities("USER").build()); return manager; } /** * 必定要將 userDetailsService 設置到 AuthenticationManagerBuilder 中 * 否則後面校驗ClientDetailsService時會找不到UsernamePasswordToken的Provider */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService()); } /** * 須要配置這個支持password模式 * support password grant type */ @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Bean public PasswordEncoder passwordEncoder() { return PasswordEncoderFactories.createDelegatingPasswordEncoder(); } }
校驗資源
zuizuideMacBook-Pro:~ zuizui$ curl -i localhost:8080/api/public/1 HTTP/1.1 200 X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY Content-Type: text/plain;charset=UTF-8 Content-Length: 16 Date: Sun, 05 May 2019 06:15:16 GMT this is public 1
zuizuideMacBook-Pro:~ zuizui$ curl -i localhost:8080/api/protect/1 HTTP/1.1 401 Set-Cookie: JSESSIONID=EB613FD5D191BAE6AAF2F20FCC1358B6; Path=/; HttpOnly Cache-Control: no-store Pragma: no-cache WWW-Authenticate: Bearer realm="oauth2-resource", error="unauthorized", error_description="Full authentication is required to access this resource" X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block X-Frame-Options: DENY Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Sun, 05 May 2019 06:15:53 GMT {"error":"unauthorized","error_description":"Full authentication is required to access this resource"}
獲取token
zuizuideMacBook-Pro:~ zuizui$ curl -H "Authorization:Basic ZGVtb0FwcDpkZW1vQXBwU2VjcmV0" -i -d "grant_type=password&scope=all&username=demoUser1&password=123456" http://localhost:8080/oauth/token HTTP/1.1 200 Cache-Control: no-store Pragma: no-cache X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block X-Frame-Options: DENY Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Mon, 06 May 2019 01:35:06 GMT {"access_token":"db51190d-eaa1-44f8-b61f-dbd97b5f401d","token_type":"bearer","refresh_token":"aef12b97-a2d6-48cd-afba-d88c5e0ad51f","expires_in":1088,"scope":"all"}
經過token訪問資源
zuizuideMacBook-Pro:~ zuizui$ curl -i http://localhost:8080/api/protect/111 -H "Authorization: Bearer db51190d-eaa1-44f8-b61f-dbd97b5f401d" HTTP/1.1 200 Set-Cookie: JSESSIONID=B793E39D6562AD2DDA09E04CF849E1DA; Path=/; HttpOnly X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY Content-Type: text/plain;charset=UTF-8 Content-Length: 19 Date: Mon, 06 May 2019 01:36:08 GMT this is protect 111
刷新token
zuizuideMacBook-Pro:~ zuizui$ curl -i http://localhost:8080/oauth/token -d "grant_type=refresh_token&refresh_token=ebf6584f-45d7-4e14-b224-9bdb3a30d684&client_id=demoApp&client_secret=demoAppSecret" HTTP/1.1 200 Cache-Control: no-store Pragma: no-cache X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block X-Frame-Options: DENY Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Mon, 06 May 2019 02:04:45 GMT {"access_token":"a13eb573-1946-4bf5-a885-f05039aaf981","token_type":"bearer","refresh_token":"49bb3cd9-6cd2-4d49-91d0-da76de72c36a","expires_in":1199,"scope":"all"}
WebSecurityConfigurerAdapter和ResourceServerConfigurerAdapter
- WebSecurityConfigurerAdapter用於保護oauth相關的endpoints,同時主要做用於用戶的登陸(
form login
,Basic auth
) - ResourceServerConfigurerAdapter用於保護oauth要開放的資源,同時主要做用於client端以及token的認證(
Bearer auth
)
所以兩者是分工協做的
- 在WebSecurityConfigurerAdapter不攔截oauth要開放的資源
- 在ResourceServerConfigurerAdapter配置須要token驗證的資源
authorization_code
在以前的基礎上增長受權類型的配置
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("demoApp") .secret(passwordEncoder.encode("demoAppSecret")) .authorizedGrantTypes("client_credentials", "password", "refresh_token", "authorization_code") .scopes("all") .resourceIds("oauth2-resource") .accessTokenValiditySeconds(1200) .refreshTokenValiditySeconds(50000); }
一、請求受權碼
GET http://localhost:8080/oauth/authorize?response_type=code&client_id=demoApp&redirect_uri=http://baidu.com
二、在頁面進行受權,跳轉到redirect_uri,並帶上了受權碼。
三、經過受權碼獲取token
zuizuideMacBook-Pro:~ zuizui$ curl -i -d "grant_type=authorization_code&code=Fxa2B9&client_id=demoApp&client_secret=demoAppSecret&redirect_uri=http://baidu.com&scope=all" -X POST http://localhost:8080/oauth/token HTTP/1.1 200 Cache-Control: no-store Pragma: no-cache X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block X-Frame-Options: DENY Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Mon, 06 May 2019 08:44:52 GMT {"access_token":"af929ab8-333c-4e5d-845a-2fe6a347c3ff","token_type":"bearer","refresh_token":"f186692e-8b39-444a-9554-54777bbf74fa","expires_in":1120,"scope":"all"}
四、使用token訪問資源
zuizuideMacBook-Pro:~ zuizui$ curl -i -H "Authorization: bearer 833a13f0-f665-4528-8536-6d79c06a1f74" http://localhost:8080/api/protect/11111 HTTP/1.1 200 Set-Cookie: JSESSIONID=AEEBE7A26AB987143CB6E9486B1B31AB; Path=/; HttpOnly X-Content-Type-Options: nosniff X-XSS-Protection: 1; mode=block Cache-Control: no-cache, no-store, max-age=0, must-revalidate Pragma: no-cache Expires: 0 X-Frame-Options: DENY Content-Type: text/plain;charset=UTF-8 Content-Length: 21 Date: Mon, 06 May 2019 09:04:24 GMT this is protect 11111