美文网首页
spring security oauth2实践

spring security oauth2实践

作者: 饿了爸 | 来源:发表于2019-08-15 10:27 被阅读0次

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

    相关文章

      网友评论

          本文标题:spring security oauth2实践

          本文链接:https://www.haomeiwen.com/subject/budajctx.html