【问题标题】:spring boot oauth2 - cannot obtain access token when use Basic Authspring boot oauth2 - 使用基本身份验证时无法获取访问令牌
【发布时间】:2018-06-22 18:13:46
【问题描述】:

我无法从我的 spring-boot 服务器 v.2.0.3.RELEASE 获取访问令牌。我使用 spring-security-oauth v.2.3.3.RELEASE。 当我使用邮递员时,我可以获得访问令牌,并且在日志中我看到 BasicAuthenticateFilter 是匹配的。但是当使用 angularjs/react 时,BasicAuthenticateFilter 被省略了,我得到了 401,没有任何消息。

身份验证服务器

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

static final String CLIENT_ID = "client";
static final String CLIENT_SECRET = "$2a$04$AMTwWHtjscVAHH4gPHx04.82v/W80KVJptp0l/QUWrlkiWU7g7wbe";
static final String GRANT_TYPE = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static int ACCESS_TOKEN_VALIDITY_SECONDS = 2*60*60;
static final int REFRESH_TOKEN_VALIDITY_SECONDS = 6*60*60;

@Autowired
private TokenStore tokenStore;

@Autowired
private AuthenticationManager authenticationManager;

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients
            .inMemory()
            .withClient(CLIENT_ID)
            .secret(CLIENT_SECRET)
            .authorizedGrantTypes(GRANT_TYPE, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT)
            .scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
            .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
            .refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS);
}


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

@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
    PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
    return propertySourcesPlaceholderConfigurer;
}
}

安全配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Resource(name = "userService")
private UserDetailsService userDetailsService;

@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}



@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService)
            .passwordEncoder(encoder());
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .csrf().disable()
    .authorizeRequests()
            .antMatchers("/login").permitAll()
            .antMatchers("/oauth/token").permitAll()
            .anyRequest().authenticated();
}

@Bean
public BCryptPasswordEncoder encoder() {
    return new BCryptPasswordEncoder();
}

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

@Bean
public FilterRegistrationBean corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/**", config);
    FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));
    bean.setOrder(50);
    return bean;
}
}

资源服务器

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = "resource_id";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId(RESOURCE_ID);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/h2-console/**").permitAll()
                .antMatchers("/user/register","/user/login").permitAll()
                .antMatchers("/**").authenticated()
                .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler())
        .and().headers().frameOptions().disable();
    }
}

angularjs 代码

angular.module('myApp.view1', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl'
 });
}])

.controller('View1Ctrl', ['$http','$httpParamSerializer', function($http, $httpParamSerializer) {
var ctrl = this;
this.data = {
    grant_type:"password",
    username: "",
    password: "",
    client_id: "client"
};
this.encoded = btoa("client:secret");

this.login = function() {
    var req = {
        method: 'POST',
        url: "http://localhost:8080/api/oauth/token",
        headers: {
            "Authorization": "Basic " + ctrl.encoded,
            "Content-type": "application/x-www-form-urlencoded; charset=utf-8"
        },
        data: $httpParamSerializer(ctrl.data)
    }
    $http(req).then(function(data){
      console.log(data);
        $http.defaults.headers.common.Authorization =
            'Bearer ' + data.data.access_token;
        $cookies.put("access_token", data.data.access_token);
        window.location.href="index";
    }, function(error) {
      console.log(error);
    });
}
}]);

这是我的 spring-boot 日志

2018-06-22 19:01:45.134  INFO 23778 --- [nio-8080-exec-3] o.a.c.c.C.[Tomcat].[localhost].[/api]    : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-06-22 19:01:45.134  INFO 23778 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2018-06-22 19:01:45.143  INFO 23778 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 9 ms
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/oauth/token']
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/oauth/token'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher  : matched
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', GET]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'OPTIONS /oauth/token' doesn't match 'GET /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', POST]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'OPTIONS /oauth/token' doesn't match 'POST /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', PUT]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'OPTIONS /oauth/token' doesn't match 'PUT /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher  : Trying to match using Ant [pattern='/logout', DELETE]
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Request 'OPTIONS /oauth/token' doesn't match 'DELETE /logout
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.web.util.matcher.OrRequestMatcher  : No matches found
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2018-06-22 19:01:45.144 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 6 of 11 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 7 of 11 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 8 of 11 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter  : Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@64454d87: Principal: anonymousUser; 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: ROLE_ANONYMOUS'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 9 of 11 in additional filter chain; firing Filter: 'SessionManagementFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : /oauth/token at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/oauth/token'; against '/oauth/token'
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /oauth/token; Attributes: [fullyAuthenticated]
2018-06-22 19:01:45.145 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@64454d87: Principal: anonymousUser; 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: ROLE_ANONYMOUS
2018-06-22 19:01:45.146 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@62efc6af, returned: -1
2018-06-22 19:01:45.153 DEBUG 23778 --- [nio-8080-exec-3] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is anonymous); redirecting to authentication entry point

org.springframework.security.access.AccessDeniedException: Access is denied

【问题讨论】:

    标签: spring spring-boot oauth-2.0


    【解决方案1】:

    我找到了解决问题的方法。主要问题是向 oauth/token 发送 OPTIONS 请求。我更改了我的 CorsFilter 和 SecurityConfig。

    SecurityConfig.java

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/oauth/token").permitAll();
    }
    

    SimpleCorsFilter.java

    @Component
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class SimpleCorsFilter implements Filter {
    
        public SimpleCorsFilter() {
        }
    
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
            HttpServletResponse response = (HttpServletResponse) res;
            HttpServletRequest request = (HttpServletRequest) req;
            response.setHeader("Access-Control-Allow-Origin", "*");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization");
    
            if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
                response.setStatus(HttpServletResponse.SC_OK);
            } else {
                chain.doFilter(req, res);
            }
        }
    
        @Override
        public void init(FilterConfig filterConfig) {
        }
    
        @Override
        public void destroy() {
        }
    }
    

    更改后我得到了访问令牌

    【讨论】:

      猜你喜欢
      • 2016-09-15
      • 2018-09-07
      • 2019-10-25
      • 2020-03-03
      • 2016-07-06
      • 2014-12-17
      • 2021-05-12
      • 1970-01-01
      • 2015-11-02
      相关资源
      最近更新 更多