Spring Security OAuth - 拒绝访问

时间:2015-08-19 17:31:38

标签: java spring oauth spring-security spring-security-oauth2

不确定我在哪里配置错误的AuthorizationServer。代码成功从db中检索使用,然后出于某种原因我收到此错误:Access is denied (user is not anonymous); delegating to AccessDeniedHandler。 (请参阅Auth服务器日志HERE)并不是用户登录以执行授权的全部原因。

我需要在哪里指定谁可以访问哪些内容?

授权服务器

@SpringBootApplication
@ComponentScan(basePackages = {"com.web.authserver"})
@EntityScan(basePackages = {"com.web.entity", "com.web.authserver"})
public class HLOAuth2AuthServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(HLOAuth2AuthServerApplication.class, args);
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

        @Autowired
        DataSource dataSource;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints
                    .tokenStore(tokenStore())
                    .approvalStore(approvalStore())
                    .authorizationCodeServices(authorizationCodeServices());
        }

        @Bean
        public JdbcClientDetailsService clientDetailsService() {
            return new JdbcClientDetailsService(dataSource);
        }

        @Bean
        public TokenStore tokenStore() {
            return new JdbcTokenStore(dataSource);
        }

        @Bean
        public ApprovalStore approvalStore() {
            return new JdbcApprovalStore(dataSource);
        }

        @Bean
        public AuthorizationCodeServices authorizationCodeServices() {
            return new JdbcAuthorizationCodeServices(dataSource);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.withClientDetails(clientDetailsService());
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            oauthServer

                    // will be applied to       /oauth/token_key
                    .tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_USER')")

                    // will be application to   /oauth/check_token
                    .checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT') || hasAuthority('ROLE_USER') || hasAuthority('USER')")

                    .allowFormAuthenticationForClients();

        }
    }


    @Configuration
    protected static class AuthenticationManagerConfiguration extends GlobalAuthenticationConfigurerAdapter {

        @Autowired
        private CustomUserDetailsService customUserDetailsService;

        @Override
        public void init(AuthenticationManagerBuilder auth) throws Exception {
            // @formatter:off
            auth
                .userDetailsService(customUserDetailsService)
                .passwordEncoder(new BCryptPasswordEncoder());
            // @formatter:on
        }
    }
}

资源服务器:

package com.hl.resources.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.oauth2.client.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.configurers.*;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;

import javax.sql.DataSource;


@Configuration
@EnableResourceServer
public class OAuth2ResourceConfig extends ResourceServerConfigurerAdapter{

    @Autowired
    DataSource dataSource;

    String RESOURCE_ID = "hl_data_resource";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        TokenStore tokenStore = new JdbcTokenStore(dataSource);
        resources
                .resourceId(RESOURCE_ID)
                .tokenStore(tokenStore);
    }



    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.
                anonymous()
                .and().requestMatchers().antMatchers("/api/v1/users/user")
                .and().authorizeRequests().antMatchers("/api/v1/users/user").access("#oauth2.hasScope('read')");

        http
                // For some reason we cant just "permitAll" OPTIONS requests which are needed for CORS support. Spring Security
                // will respond with an HTTP 401 nonetheless.
                // So we just put all other requests types under OAuth control and exclude OPTIONS.
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')")
                .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')")
                .and()

                // Add headers required for CORS requests.
                .headers().addHeaderWriter((request, response) -> {
            response.addHeader("Access-Control-Allow-Origin", "*");

            if (request.getMethod().equals("OPTIONS")) {
                response.setHeader("Access-Control-Allow-Methods", request.getHeader("Access-Control-Request-Method"));
                response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));
            }
        });

        http.authorizeRequests().antMatchers(HttpMethod.POST, "/v1/files/**").permitAll();
        // @formatter:off
//         http
//         .requestMatchers().antMatchers("/bookmarks", "/bookmarks/**")
//         .and()
//         .authorizeRequests().anyRequest().access("#oauth2.hasScope('write')");
         // @formatter:on

    }

}

网络客户端应用

@SpringBootApplication
@EnableZuulProxy
@EnableOAuth2Sso
@EnableConfigurationProperties
public class HLOAuth2TestWebClientApplication {

    public static void main(String[] args) {
        SpringApplication.run(HLOAuth2TestWebClientApplication.class, args);
    }

    @Configuration
    @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
    protected static class SecurityConfiguration extends OAuth2SsoConfigurerAdapter {

        @Autowired
        OAuth2SsoProperties oAuth2SsoProperties;

        @Override
        public void match(RequestMatchers matchers) {
            matchers.anyRequest();
        }

        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/index.html", "/home.html" ,"/login").permitAll()

                    .anyRequest().authenticated()

                    .and().csrf().csrfTokenRepository(csrfTokenRepository())
                    .and().addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
            //.and().csrf().disable()
            ;
        }

        private Filter csrfHeaderFilter() {
            return new OncePerRequestFilter() {
                @Override
                protected void doFilterInternal(HttpServletRequest request,
                                                HttpServletResponse response, FilterChain filterChain)
                        throws ServletException, IOException {
                    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
                            .getName());
                    if (csrf != null) {
                        Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                        String token = csrf.getToken();
                        if (cookie == null || token != null
                                && !token.equals(cookie.getValue())) {
                            cookie = new Cookie("XSRF-TOKEN", token);
                            cookie.setPath("/");
                            response.addCookie(cookie);
                        }
                    }
                    filterChain.doFilter(request, response);
                }
            };
        }


        private CsrfTokenRepository csrfTokenRepository() {
            HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
            repository.setHeaderName("X-XSRF-TOKEN");
            return repository;
        }
    }
}

Web客户端application.properties文件:

server.port=7070
server.context-path=
server.tomcat.basedir=target/tomcat
vaadin.servlet.url-mapping=/ui
security.basic.enabled=false
debug=true
logging.level.org.springframework.security=DEBUG

#spring.oauth2.sso.home.secure=false
#spring.oauth2.sso.home.path=/,/**/*.html
spring.oauth2.client.accessTokenUri = http://localhost:9090/a/oauth/token
spring.oauth2.client.userAuthorizationUri = http://localhost:9090/a/oauth/authorize
spring.oauth2.client.clientId = acme
spring.oauth2.client.id=testWebClient
spring.oauth2.client.clientSecret = acmesecret
spring.oauth2.client.scope[0]=openid
spring.oauth2.client.scope[1]=read
#spring.oauth2.client.grant-type=implicit
spring.oauth2.client.clientAuthenticationScheme = form

spring.oauth2.resource.userInfoUri = http://localhost:8080/api/v1/users/user

zuul.routes.resource.path = /resource/**
zuul.routes.resource.url = http://localhost:7070
zuul.routes.user.path = /user/**
zuul.routes.user.url = http://localhost:9090/a/v1/users/user

Web客户端服务器日志:

http://pastebin.com/raw.php?i=vi2wEzSA

授权服务器日志:

http://pastebin.com/raw.php?i=R580us0U

1 个答案:

答案 0 :(得分:5)

来自日志:

2015-08-19 09:53:52.979 DEBUG 26748 --- [nio-9090-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /oauth/authorize?client_id=acme&redirect_uri=http://localhost:7070/login&response_type=code&scope=openid%20read&state=3hSgha; Attributes: [hasAnyRole('ROLE_USER')]
2015-08-19 09:53:52.979 DEBUG 26748 --- [nio-9090-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@5e1fbc04: Principal: com.healthlinx.entity.Authority@d191b368: Username: AlexanderBaranovsky@fake.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: [UserRole(id=1, roleName=USER)]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: [UserRole(id=1, roleName=USER)]
2015-08-19 09:53:52.981 DEBUG 26748 --- [nio-9090-exec-1] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@3591ec27, returned: -1

我们可以看到用户已经过身份验证(请参阅第2行),但是 /oauth/authorize期望用户具有ROLE_USER权限(参见第1行)。

如果我们看一下第二行,日志显示用户只有USER权限,这就是WebExpressionVoter返回-1的原因。

您可以将USER授权机构更改为ROLE_USER,看看是否能解决问题。

相关问题