(八)springcloud Oauth2授权- 四种授权类型

client_credentials

1、创建应用资源

@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;
        }
    }

}

2、配置认证服务器

//提供/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);
    }

}

3、配置资源访问控制

@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();
    }
}

4、验证

1、启动应用,访问资源:

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"}

2、获取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"}

3、携带token访问资源

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

密码模式需要配置UserDetailsServiceAuthenticationManager

<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>

1、准备资源

@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;
        }
    }

}

2、认证服务器配置

@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);
    }

}

3、资源服务器配置

@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);
    }
}

4、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);
}

1、请求授权码

GET http://localhost:8080/oauth/authorize?response_type=code&client_id=demoApp&redirect_uri=http://baidu.com

2、在页面进行授权,跳转到redirect_uri,并带上了授权码。

3、通过授权码获取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"}

4、使用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
posted @ 2019-05-06 17:36  zuier~  阅读(7933)  评论(0编辑  收藏  举报