AuthenticationCredentialsNotFoundException при доступе к защищенному ресурсу

Я использую поток кода авторизации openid connect с 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
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
901
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В моей реализации было несколько проблем, основная из которых заключалась в отсутствии конечной точки userinfo в классе расширения OAuth2ProtectedResourceDetails. Вместо этого я переместил эту конфигурацию в 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

Да, я сделал шаг назад от защиты ресурса, но маленькими шагами :)

Другие вопросы по теме