zoukankan      html  css  js  c++  java
  • 原贴地址: https://segmentfault.com/a/1190000012260914#articleHeader6

    前面的一篇文章讲了spring security oauth2的client credentials授权模式,一般用于跟用户无关的,开放平台api认证相关的授权场景。本文主要讲一下跟用户相关的授权模式之一password模式。

    回顾四种模式

    OAuth 2.0定义了四种授权方式。

    • 授权码模式(authorization code)
    • 简化模式(implicit)
    • 密码模式(resource owner password credentials)
    • 客户端模式(client credentials)(主要用于api认证,跟用户无关)

    maven

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

    配置

    security config

    支持password模式要配置AuthenticationManager

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    public class SecurityConfig 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("123456").authorities("USER").build());
            manager.createUser(User.withUsername("demoUser2").password("123456").authorities("USER").build());
            return manager;
        }
    
        /**
         * 需要配置这个支持password模式
         * support password grant type
         * @return
         * @throws Exception
         */
        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    }

    这个是比client credentials模式新增的配置,主要配置用户以及authenticationManager

    auth server配置

    @Configuration
    @EnableAuthorizationServer //提供/oauth/authorize,/oauth/token,/oauth/check_token,/oauth/confirm_access,/oauth/error
    public class OAuth2ServerConfig extends AuthorizationServerConfigurerAdapter {
    
        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer
                    .tokenKeyAccess("permitAll()") //url:/oauth/token_key,exposes public key for token verification if using JWT tokens
                    .checkTokenAccess("isAuthenticated()") //url:/oauth/check_token allow check token
                    .allowFormAuthenticationForClients();
        }
        
        /**
         * 注入authenticationManager
         * 来支持 password grant type
         */
        @Autowired
        private AuthenticationManager authenticationManager;
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.authenticationManager(authenticationManager);
        }
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("demoApp")
                    .secret("demoAppSecret")
                    .authorizedGrantTypes("client_credentials", "password", "refresh_token")
                    .scopes("all")
                    .resourceIds("oauth2-resource")
                    .accessTokenValiditySeconds(1200)
                    .refreshTokenValiditySeconds(50000);
    }

    这里记得注入authenticationManager来支持password模式

    否则报错如下

    ~ curl -i -X POST -d "username=demoUser1&password=123456&grant_type=password&client_id=demoApp&client_secret=demoAppSecret" http://localhost:8080/oauth/token
    HTTP/1.1 400
    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
    X-Application-Context: application
    Cache-Control: no-store
    Pragma: no-cache
    Content-Type: application/json;charset=UTF-8
    Transfer-Encoding: chunked
    Date: Sun, 03 Dec 2017 07:01:27 GMT
    Connection: close
    
    {"error":"unsupported_grant_type","error_description":"Unsupported grant type: password"}

    resource server 配置

    @Configuration
    @EnableResourceServer
    public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
    
    //    /**
    //      * 要正常运行,需要反注释掉这段,具体原因见下面分析
    //     * 这里设置需要token验证的url
    //     * 这些需要在WebSecurityConfigurerAdapter中排查掉
    //     * 否则优先进入WebSecurityConfigurerAdapter,进行的是basic auth或表单认证,而不是token认证
    //     * @param http
    //     * @throws Exception
    //     */
    //    @Override
    //    public void configure(HttpSecurity http) throws Exception {
    //        http.requestMatchers().antMatchers("/api/**")
    //                .and()
    //                .authorizeRequests()
    //                .antMatchers("/api/**").authenticated();
    //    }
    
    
    }

    验证

    请求token

    curl -i -X POST -d "username=demoUser1&password=123456&grant_type=password&client_id=demoApp&client_secret=demoAppSecret"http://localhost:8080/oauth/token

    返回

    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
    X-Application-Context: application
    Cache-Control: no-store
    Pragma: no-cache
    Content-Type: application/json;charset=UTF-8
    Transfer-Encoding: chunked
    Date: Sun, 03 Dec 2017 04:53:40 GMT
    
    {"access_token":"4cfb16f9-116c-43cf-a8d4-270e824ce5d7","token_type":"bearer","refresh_token":"8e9bfbda-77e5-4d97-b061-4e319de7eb4a","expires_in":1199,"scope":"all"}

    携带token访问资源

    curl -i http://localhost:8080/api/blog/1?access_token=4cfb16f9-116c-43cf-a8d4-270e824ce5d7

    或者

    curl -i -H "Accept: application/json" -H "Authorization: Bearer 4cfb16f9-116c-43cf-a8d4-270e824ce5d7" -X GET http://localhost:8080/api/blog/1

    返回

    HTTP/1.1 302
    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
    Set-Cookie: JSESSIONID=F168A54F0F3C3D96A053DB0CFE129FBF; Path=/; HttpOnly
    Location: http://localhost:8080/login
    Content-Length: 0
    Date: Sun, 03 Dec 2017 05:20:19 GMT

    出错原因见下一小结

    成功返回

    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
    X-Application-Context: application
    Content-Type: text/plain;charset=UTF-8
    Content-Length: 14
    Date: Sun, 03 Dec 2017 06:39:24 GMT
    
    this is blog 1

    错误返回

    HTTP/1.1 401
    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
    Cache-Control: no-store
    Pragma: no-cache
    WWW-Authenticate: Bearer realm="oauth2-resource", error="invalid_token", error_description="Invalid access token: 466ee845-2d08-461b-8f62-8204c47f652"
    Content-Type: application/json;charset=UTF-8
    Transfer-Encoding: chunked
    Date: Sun, 03 Dec 2017 06:39:28 GMT
    
    {"error":"invalid_token","error_description":"Invalid access token: 466ee845-2d08-461b-8f62-8204c47f652"}

    WebSecurityConfigurerAdapter与ResourceServerConfigurerAdapter

    二者都有针对http security的配置,他们的默认配置如下

    WebSecurityConfigurerAdapter

    spring-security-config-4.2.3.RELEASE-sources.jar!/org/springframework/security/config/annotation/web/configuration/WebSecurityConfigurerAdapter.java

    @Order(100)
    public abstract class WebSecurityConfigurerAdapter implements
            WebSecurityConfigurer<WebSecurity> {
            //......
    protected void configure(HttpSecurity http) throws Exception {
            logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
    
            http
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .formLogin().and()
                .httpBasic();
        }
    
        //......
    }    

    可以看到WebSecurityConfigurerAdapter的order是100

    ResourceServerConfigurerAdapter

    spring-security-oauth2-2.0.14.RELEASE-sources.jar!/org/springframework/security/oauth2/config/annotation/web/configuration/ResourceServerConfigurerAdapter.java

    public void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().authenticated();
        }

    它的order是SecurityProperties.ACCESS_OVERRIDE_ORDER - 1
    spring-boot-autoconfigure-1.5.5.RELEASE-sources.jar!/org/springframework/boot/autoconfigure/security/oauth2/resource/ResourceServerProperties.java

    /**
         * The order of the filter chain used to authenticate tokens. Default puts it after
         * the actuator endpoints and before the default HTTP basic filter chain (catchall).
         */
        private int filterOrder = SecurityProperties.ACCESS_OVERRIDE_ORDER - 1;

    由此可见WebSecurityConfigurerAdapter的拦截要优先于ResourceServerConfigurerAdapter

    二者关系

    • WebSecurityConfigurerAdapter用于保护oauth相关的endpoints,同时主要作用于用户的登录(form login,Basic auth)
    • ResourceServerConfigurerAdapter用于保护oauth要开放的资源,同时主要作用于client端以及token的认证(Bearer auth)

    因此二者是分工协作的

    • 在WebSecurityConfigurerAdapter不拦截oauth要开放的资源
    @Override
        public void configure(HttpSecurity http) throws Exception {
            http.csrf().disable();
            http.requestMatchers().antMatchers("/oauth/**")
                    .and()
                    .authorizeRequests()
                    .antMatchers("/oauth/**").authenticated();
        }
    • 在ResourceServerConfigurerAdapter配置需要token验证的资源
    @Override
        public void configure(HttpSecurity http) throws Exception {
            http.requestMatchers().antMatchers("/api/**")
                    .and()
                    .authorizeRequests()
                    .antMatchers("/api/**").authenticated();
        }

    这样就大功告成

    doc

  • 相关阅读:
    ASP.NET Core 中文文档 第四章 MVC(3.2)Razor 语法参考
    ASP.NET Core 中文文档 第四章 MVC(3.1)视图概述
    ASP.NET Core 中文文档 第四章 MVC(2.3)格式化响应数据
    ASP.NET Core 中文文档 第四章 MVC(2.2)模型验证
    ASP.NET Core 中文文档 第四章 MVC(2.1)模型绑定
    ASP.NET Core 中文文档 第四章 MVC(01)ASP.NET Core MVC 概览
    mysql 解除正在死锁的状态
    基于原生JS的jsonp方法的实现
    HTML 如何显示英文单、双引号
    win2008 r2 服务器php+mysql+sqlserver2008运行环境配置(从安装、优化、安全等)
  • 原文地址:https://www.cnblogs.com/white-knight/p/9711515.html
Copyright © 2011-2022 走看看