spring security oauth2实践

1 概述

1.1 oauth2 根据使用场景不同,分成了4种模式

授权码模式(authorization code 即先登录获取code,再获取token)
简化模式(implicit 在redirect_uri 的Hash传递token; Auth客户端运行在浏览器中,如JS,Flash)
密码模式( password 将用户名,密码传过去,直接获取token)
客户端模式(client credentials 无用户,用户向客户端注册,然后客户端以自己的名义向’服务端’获取资源)

1.2 security oauth2 整合的3个核心配置类

资源服务配置 ResourceServerConfiguration
授权认证服务配置 AuthorizationServerConfiguration
security 配置 SecurityConfiguration

2 实例
2.1 主要代码

  • 认证服务器类
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    AuthenticationManager authenticationManager;
    @Autowired
    RedisConnectionFactory redisConnectionFactory;
    @Autowired
    UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //配置两个客户端,一个用于password认证一个用于client认证
        clients.inMemory().withClient("client_1")
                .resourceIds(DEMO_RESOURCE_ID)
                .authorizedGrantTypes("client_credentials")
                .scopes("select")
                .authorities("oauth2")
                .secret("123456")
                .and().withClient("client_2")
                .resourceIds(DEMO_RESOURCE_ID)
                .authorizedGrantTypes("password", "refresh_token")
                .scopes("select")
                .authorities("oauth2")
                .secret("123456");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .tokenStore(new RedisTokenStore(redisConnectionFactory))
                .tokenStore(new InMemoryTokenStore())
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService)
                // 2018-4-3 增加配置,允许 GET、POST 请求获取 token,即访问端点:oauth/token
                .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);

        endpoints.reuseRefreshTokens(true);
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        //允许表单认证
        oauthServer.allowFormAuthenticationForClients();
    }

}
  • 资源服务器认证配置类
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.resourceId(DEMO_RESOURCE_ID).stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
                // Since we want the protected resources to be accessible in the UI as well we need
                // session creation to be allowed (it's disabled by default in 2.0.6)
           .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
                .and()
                .anonymous()
                .and()
                .authorizeRequests()
            .antMatchers("/product/**").access("#oauth2.hasScope('select') and hasPermission('delete')")
                .antMatchers("/order/**").authenticated();//配置order访问控制,必须认证过后才可以访问
        // @formatter:on
    }
}
  • security 配置
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Bean
    @Override
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user_1").password("123456").authorities("USER").build());
        manager.createUser(User.withUsername("user_2").password("123456").authorities("USER").build());
        return manager;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
        http
                .requestMatchers().anyRequest()
                .and()
                .authorizeRequests()
                .antMatchers("/oauth/*").permitAll();
        // @formatter:on
    }
}
  • 测试 controller
@RestController
public class TestEndpoints {
    @GetMapping("/product/{id}")
    public String getProduct(@PathVariable String id) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return "product id : " + id;
    }
    @GetMapping("/order/{id}")
    public String getOrder(@PathVariable String id) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return "order id : " + id;
    }
}

2.2 测试验证

2.2.1 请求方式说明
1. /oauth/authorize:授权端点。
2. /oauth/token:获取token。
3. /oauth/confirm_access:用户确认授权提交端点。
4. /oauth/error:授权服务错误信息端点。
5. /oauth/check_token:用于资源服务访问的令牌解析端点。
6. /oauth/token_key:提供公有密匙的端点,如果你使用JWT令牌话。
7. /oauth/logout: 退出
2.2.2 未授权访问资源
curl -X GET http://localhost:8080/order/1 -H 'cache-control: no-cache'

{
    "error": "unauthorized",
    "error_description": "Full authentication is required to access this resource"
}
2.2.3 密码模式获取token

curl -X GET \
  'http://127.0.0.1:8080/oauth/token?username=user_1&password=123456&grant_type=password&client_id=client_2&client_secret=123456' \
  -H 'Postman-Token: fa9a639f-4401-4d47-9de2-11e010913905' \
  -H 'cache-control: no-cache'

{
    "access_token": "4be14cf1-2049-4bec-b7e6-27805500e8d8",
    "token_type": "bearer",
    "refresh_token": "86f583ae-7f0c-4cf7-934c-47435a1f0b9c",
    "expires_in": 37729,
    "scope": "select"
}
2.2.4 客户端模式获取token
curl -X GET \
  'http://127.0.0.1:8080/oauth/token?grant_type=client_credentials\
&client_id=client_1&client_secret=123456' 
  -H 'cache-control: no-cache'

{
    "access_token": "655e2f3c-7b58-45d7-b331-8d9784eabb21",
    "token_type": "bearer",
    "expires_in": 43098,
    "scope": "select"
}
2.2.4 授权码模式获取token
2.2.7 带错误token 访问资源
curl -X GET \
  'http://localhost:8080/order/1?access_token=9363651c-d354-41d3-89dc-89607665b351' \
  -H 'cache-control: no-cache'

{
    "error": "invalid_token",
    "error_description": "Invalid access token: 9363651c-d354-41d3-89dc-89607665b351"
}
2.2.6 带正确token 访问资源
curl -X GET \
  'http://localhost:8080/order/1?access_token=c363651c-d354-41d3-89dc-89607665b351' \
  -H 'cache-control: no-cache'

order id : 1
2.2.7 密码模式刷新token
curl -X GET \
  'http://localhost:8080/oauth/token?grant_type=refresh_token&refresh_token=2c24fdba-7c7a-409d-ac1d-3af411aa3dc5&client_id=client_2&client_secret=123456' \
  -H 'cache-control: no-cache'

{
    "access_token": "eaf7dad3-789e-4bd5-9e3c-0a8c3801a285",
    "token_type": "bearer",
    "refresh_token": "2c24fdba-7c7a-409d-ac1d-3af411aa3dc5",
    "expires_in": 43199,
    "scope": "select"
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,884评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,212评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,351评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,412评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,438评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,127评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,714评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,636评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,173评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,264评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,402评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,073评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,763评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,253评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,382评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,749评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,403评论 2 358