spring security oauth2 password授权模式

瘢壳接口
• 阅读 44269

前面的一篇文章讲了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

点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
IdentityServer4在Asp.Net Core中的应用(一)
  IdentityServer4是一套身份授权以及访问控制的解决方案,专注于帮助使用.Net技术的公司为现代应用程序建立标识和访问控制解决方案,包括单点登录、身份管理、授权和API安全。  下面我将具体介绍如何在.NetCore中实现OAuth授权,从最简单的授权模式开始,在上一篇对OAuth2.0的详细描述中,在客户端模式中,我们说它在严
Stella981 Stella981
3年前
OAuth2.0 授权码理解
OAuth2.0授权模式本篇文章介绍OAuth的经典授权模式,授权码模式所谓授权无非就是授权与被授权,被授权方通过请求得到授权方的同意,并赋予某用权力,这个过程就是授权。那作为授权码就更加简单,第三方直接发起授权请求并希望能够得到某种我需要的权力。授权方根据第三方的需求提供相应的授权权限,最后生成一串付有权限的码来实现授权,这个
Stella981 Stella981
3年前
Apache Shiro反序列化识别那些事
1.1关于ApacheShiroApacheshiro是一个Java安全框架,提供了认证、授权、加密和会话管理功能,为解决应⽤安全提供了相应的API:1.认证⽤用户身份识别,常被称为用户”登录”2.授权访问控制3.密码加密保护或隐藏数据防止被偷窥4.会话管理用户相关的时间敏感的状态1.2Shiro反序列化
Stella981 Stella981
3年前
Spring Boot 的 oAuth2 认证(附源码)
OAuth2统一认证原理OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(authorizationlayer)。"客户端"不能直接登录"服务提供商",只能登录授权层,以此将用户与客户端区分开来。"客户端"登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围
Easter79 Easter79
3年前
SpringSecurity进阶:OAuth2.0详解
OAuth2是什么?OAuth是一个为了方便用户登入而使用的授权流程,他的优点是不需要向第三方平台暴露我们的用户名和密码,而是使用授权服务器颁发短期的token和效验token的方式开放部分资源给第三方平台OAuth是一个授权协议不是认证协议OAuth2的授权方式!(https://p1tt
Wesley13 Wesley13
3年前
5 分钟部署一个 OAuth2 服务并对接 Shibboleth
前言这还是一个标题党。OAuth2现在已经是开放授权协议的事实标准,你可以看到几乎所有的xxx开放平台均采取的OAuth2协议来进行授权。而在AuthorizationCode模式的基础上结合JWT,标准化的userinfoendpoint和服务发现,就成了OpenIDConnect。当然即便不加上这些限定,OA
Stella981 Stella981
3年前
Hive在SQL标准权限模式下创建UDF失败的问题排查
环境:CDH5.16Hive1.1.0已开启KerberosHive授权使用SQLStandardsBasedAuthorization模式(以下简称SSBA模式)症状表现:在编译好UDF的jar包之后,上传到HDFS目录。hdfs dfsmkdi
Wesley13 Wesley13
3年前
C#开发——网站应用微信登录开发
1\.在微信开放平台注册开发者账号,并有一个审核已通过的网站应用,并获得相对应的AppID和AppSecret,申请通过登陆后,方可开始接入流程。2.微信OAuth2.0授权登录目前支持authorization\_code模式,适用于拥有server端的应用授权。该模式整体流程为:1.第三方发起微信授权登录请求,微信用户允许授权第三方应
Wesley13 Wesley13
3年前
usage权限的使用与管理
目录文档用途详细信息文档用途了解usage权限的使用与管理详细信息场景1:只授权usageonschema权限session1:\创建test用户,并将highgo模式赋予test用户。highgo
Easter79 Easter79
3年前
SpringCloud Alibaba微服务实战十八
!(https://oscimg.oschina.net/oscnet/2f4a69393b334d78bb0a4efeddf8e21f.png)概述大家都知道在oauth2认证体系中有四种授权模式:授权码模式(authorizationcode)简化模式(implicit)客户
Wesley13 Wesley13
3年前
THINKPHP日常用到的基础知识
一、分组模式相关1、何时用分组模式一般情况下,在有前台跟后台甚至用户中心的时候,用到分组模式用的比较多2、如何使用分组模式项目文件夹里面会有个Conf文件夹,这里用于系统的配置,一般情况下只有一个config.php,但用到分组模式后,我们在里面一般会建几个文件夹,分别用于前后台的配置,比方说我们建立了Adm
瘢壳接口
瘢壳接口
Lv1
野火烧不尽,春风吹又生。
文章
2
粉丝
0
获赞
0