访问受保护的资源时出现AuthenticationCredentialsNotFoundException

时间:2018-08-09 22:22:53

标签: spring-security login authorization openid-connect

我正在使用openid的授权代码流与springboot连接。 我在本地主机上运行2服务。一个托管受保护资源,另一个是客户端。他们现在在同一个项目中,因为这只是概念的证明。

当用户尝试访问主页时,我想将他们重定向到我们的自定义登录页面。授权后,我要允许他们访问受保护的资源

我的客户端配置:

@Configuration
@EnableOAuth2Client
@EnableWebSecurity
@ComponentScan("com.myclient”)
@Profile({"dev"})
public class OpenIdConnectClientConfig extends WebSecurityConfigurerAdapter {


@Override
public void configure(HttpSecurity http) throws Exception { 
    http
    .antMatcher("/**").authorizeRequests()
    .antMatchers("/login**", “/##/token.oauth2", “/##/authorization.oauth2").permitAll()
    .and()
    .anonymous().disable()
    .logout()
        .permitAll()
        .deleteCookies("remove")
        .clearAuthentication(true)
        .invalidateHttpSession(true)
        .logoutSuccessUrl("https://mylogout/logout")
    .and().httpBasic().disable();
}// @formatter:on


@Override 
public void configure(WebSecurity web)  throws Exception {// @formatter:off
    web
    .ignoring()
        .mvcMatchers(
                "/favicon.ico",
                "/webjars/**",
                "/css/**");
}// @formatter:on


// thymeleaf

@Bean
public ClassLoaderTemplateResolver templateResolver() {
    final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
    templateResolver.setPrefix("templates/");
    templateResolver.setSuffix(".html");
    return templateResolver;
}

@Bean
public SpringTemplateEngine templateEngine() {
    final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
    templateEngine.setTemplateResolver(templateResolver());
    return templateEngine;
}

@Bean
public ThymeleafViewResolver viewResolver() {
    final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    viewResolver.setTemplateEngine(templateEngine());
    return viewResolver;
}

// end thymeleaf


@Configuration
@EnableOAuth2Client
protected static class OAuthClientConfig {
    @Bean
    public OAuth2ProtectedResourceDetails resourceDetails() {
        final AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
        details.setClientId(“#######”);
        details.setClientSecret(“#######”);
        details.setAccessTokenUri("https://tokenserver/as/token.oauth2");
        details.setUserAuthorizationUri("https://authserver/as/authorization.oauth2");
        details.setScope(Arrays.asList("openid"));
        details.setGrantType("authorization_code");
        details.setPreEstablishedRedirectUri("https://localhost:8443/login");
        details.setUseCurrentUri(false);
        return details;
    }

    @Bean
    public OAuth2RestTemplate restTemplate(final OAuth2ClientContext clientContext) {
        return new OAuth2RestTemplate(resourceDetails(), clientContext);

    }
}
 }

我正在为客户端使用以下软件包:

    <!-- security -->

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
        <version>2.0.0.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
        <version>2.0.3.RELEASE</version>
    </dependency>

我的资源服务器配置如下:

@Configuration
@EnableResourceServer
@Profile({"dev"})
public class ResourceServerConfig extends 
ResourceServerConfigurerAdapter {


@Override
public void configure(HttpSecurity http) throws Exception {// @formatter:off
    http
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()
    .authorizeRequests()
        .antMatchers("/api/**").permitAll()
        .antMatchers("/login**", "/##/token.oauth2", "/as/authorization.oauth2").permitAll()
        // .antMatchers("/**").hasAuthority("ROLE_USER")

    .and()
    .logout()
        .deleteCookies("remove")
        .invalidateHttpSession(true)
        .permitAll()
    .and()
    .csrf().disable();
}// @formatter:on  

@Bean
public ResourceServerTokenServices tokenService() {
   RemoteTokenServices tokenServices = new RemoteTokenServices();
   tokenServices.setClientId(“####”);
   tokenServices.setClientSecret(“#####”);       
   tokenServices.setCheckTokenEndpointUrl("https://tokenserver/##/token.oauth2");
   return tokenServices;
}


@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
  resources.tokenServices(this.tokenService());
}    
}

我正在使用以下软件包:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
        <version>2.0.3.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.security.oauth</groupId>
        <artifactId>spring-security-oauth2</artifactId>
        <version>2.3.3.RELEASE</version>
    </dependency>

我的客户端控制器尝试像这样访问此资源:

@RestController
@Profile({"dev"})
class MainController {

@Autowired
private OAuth2RestTemplate restTemplate;


@RequestMapping("/somepath")
public final String home() {
    return "/";
}

@SuppressWarnings("unused")
@RequestMapping
public ModelAndView login() {

    // OAuth2AccessToken accessToken = restTemplate.getAccessToken();

    final HelloWorld helloWorld = restTemplate.getForObject("https://localhost:8444/openidconnect-resource-server/api/1", HelloWorld.class);

    return new ModelAndView("landingPage");
}
}

不幸的是,我不断出现以下错误:


OrderedRequestContextFilter  : Bound request context to thread: org.apache.catalina.connector.RequestFacade@7e4514ea
AntPathRequestMatcher  : Request '/login' matched by universal pattern '/**'
security.web.FilterChainProxy        : /login?code=#####&state=## at position 1 of 10 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
security.web.FilterChainProxy        : /login?code=######&state=## at position 2 of 10 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
HttpSessionSecurityContextRepository : No HttpSession currently exists
HttpSessionSecurityContextRepository : No SecurityContext was available from the HttpSession: null. A new one will be created.
security.web.FilterChainProxy        : /login?code=####&state=## at position 3 of 10 in additional filter chain; firing Filter: 'HeaderWriterFilter'
security.web.FilterChainProxy        : /login?code=#####&state=## at position 4 of 10 in additional filter chain; firing Filter: 'CsrfFilter'
security.web.FilterChainProxy        : /login?code=####&state=## at position 5 of 10 in additional filter chain; firing Filter: 'LogoutFilter'
matcher.AntPathRequestMatcher  : Request 'GET /login' doesn't match 'POST /logout
security.web.FilterChainProxy        : /login?code=XRuHsIOKxNEzUkljeWn7lVfZcxTisziI7ZsAAADJ&state=UV13ug at position 6 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
security.web.FilterChainProxy        : /login?code=XRuHsIOKxNEzUkljeWn7lVfZcxTisziI7ZsAAADJ&state=UV13ug at position 7 of 10 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
security.web.FilterChainProxy        : /login?code=XRuHsIOKxNEzUkljeWn7lVfZcxTisziI7ZsAAADJ&state=UV13ug at position 8 of 10 in additional filter chain; firing Filter: 'SessionManagementFilter'
security.web.FilterChainProxy        : /login?code=XRuHsIOKxNEzUkljeWn7lVfZcxTisziI7ZsAAADJ&state=UV13ug at position 9 of 10 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
security.web.FilterChainProxy        : /login?code=XRuHsIOKxNEzUkljeWn7lVfZcxTisziI7ZsAAADJ&state=UV13ug at position 10 of 10 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
AntPathRequestMatcher  : Request 'GET /login' doesn't match 'POST /logout
AntPathRequestMatcher  : Checking match of request : '/login'; against '/actuator/health'
AntPathRequestMatcher  : Checking match of request : '/login'; against '/login**'
FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /login?code=#####&state=##; Attributes: [permitAll]
audit.listener.AuditListener     : AuditEvent [timestamp=2018-08-07T22:28:38.785Z, principal=, type=AUTHENTICATION_FAILURE, data={type=org.springframework.security.authentication.AuthenticationCredentialsNotFoundException, message=An Authentication object was not found in the SecurityContext}]
ExceptionTranslationFilter     : Authentication exception occurred; redirecting to authentication entry point

org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext

1 个答案:

答案 0 :(得分:0)

我的实现存在几个问题,主要的问题是OAuth2ProtectedResourceDetails扩展类中不包括userinfo端点。我将该配置移至application.properties。

我的客户端配置现在看起来像:

@Configuration
@EnableOAuth2Sso
@ComponentScan("com.myclient")
@Profile({"dev"})
public class OIDCClientConfig extends WebSecurityConfigurerAdapter {


@Override
public void configure(HttpSecurity http) throws Exception {// @formatter:off
    http
    .authorizeRequests()
        .antMatchers("/login").permitAll()
        .antMatchers("/**").hasRole("USER")
        .and()
    .csrf().disable()
    .logout()
        .permitAll()
        .deleteCookies("remove")
        .clearAuthentication(true)
        .invalidateHttpSession(true)
        .logoutSuccessUrl("https://####/logout")
    .and().httpBasic().disable();
}// @formatter:on


@Override
public void configure(WebSecurity web)  throws Exception {// @formatter:off
    web
    .ignoring()
        .mvcMatchers(
                "/**/favicon.ico",
                 "/webjars/**");
}// @formatter:on


// thymeleaf

@Bean
public ClassLoaderTemplateResolver templateResolver() {
    final ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
    templateResolver.setPrefix("templates/");
    templateResolver.setSuffix(".html");
    return templateResolver;
}

@Bean
public SpringTemplateEngine templateEngine() {
    final SpringTemplateEngine templateEngine = new SpringTemplateEngine();
    templateEngine.setTemplateResolver(templateResolver());
    return templateEngine;
}

@Bean
public ThymeleafViewResolver viewResolver() {
    final ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    viewResolver.setTemplateEngine(templateEngine());
    return viewResolver;
}

// end thymeleaf

}

我的MainController看起来像这样:

package myclient.controller;

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;

@RestController
class MainController {

@RequestMapping(value = "/home")
public ModelAndView landingPage() {
    return new ModelAndView("landingPage");
}
}

我的application.properties看起来像这样:

# Allow Thymeleaf templates to be reloaded at dev time
spring.thymeleaf.cache=false

server.tomcat.accesslog.enabled=true
server.tomcat.basedir=target/tomcat
server.ssl.key-store-type=JKS
server.ssl.key-store=classpath:keystore
server.ssl.key-store-password=changeit
server.ssl.key-alias=tomcat
server.port=8443

#context path
server.servlet.context-path=/

spring.main.web-application-type=SERVLET
spring.main.banner-mode=off
spring.profiles.active=default,dev


# spring.profiles.active=dev

# SECURITY OAUTH2 CLIENT (OAuth2ClientProperties)
security.oauth2.client.client-id=####
security.oauth2.client.client-secret=#####
security.oauth2.client.authorized-grant-types=authorization_code
security.oauth2.client.access-token-uri=https://###/##/###
security.oauth2.client.user-authorization-uri=https://###/##/###
security.oauth2.client.scope=openid
security.oauth2.client.use-current-uri=true
security.oauth2.resource.user-info-uri=####


logging.level.org.springframework=DEBUG

是的,我从保护资源上退了一步,但走了一步:)