spring boot oauth2-使用基本身份验证时无法获取访问令牌

时间:2018-06-22 18:13:47

标签: spring spring-boot oauth-2.0

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

AuthenticationServer

@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;
}
}

SecurityConfig

@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;
}
}

ResourceServer

@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

1 个答案:

答案 0 :(得分:0)

我找到了解决我问题的方法。主要问题是将OPTIONS请求发送到oauth / token。我更改了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() {
    }
}

更改之后,我获得了访问令牌