Próbuję wywołać punkty końcowe REST w jednej aplikacji (aplikacja rozruchu sprężynowego) z innej (angularjs). Aplikacje działają na następujących hostach i portach.
- Aplikacja REST za pomocą rozruchu sprężynowego,
http://localhost:8080
- Aplikacja HTML, wykorzystująca angularjs,
http://localhost:50029
Używam również spring-security
z aplikacją Spring-Boot. Z aplikacji HTML mogę uwierzytelnić się w aplikacji REST, ale potem nadal nie mogę uzyskać dostępu do żadnego punktu końcowego REST. Na przykład mam usługę angularjs zdefiniowaną w następujący sposób.
adminServices.factory('AdminService', ['$resource', '$http', 'conf', function($resource, $http, conf) {
var s = {};
s.isAdminLoggedIn = function(data) {
return $http({
method: 'GET',
url: 'http://localhost:8080/api/admin/isloggedin',
withCredentials: true,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
};
s.login = function(username, password) {
var u = 'username=' + encodeURI(username);
var p = 'password=' + encodeURI(password);
var r = 'remember_me=1';
var data = u + '&' + p + '&' + r;
return $http({
method: 'POST',
url: 'http://localhost:8080/login',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
});
};
return s;
}]);
Kontroler angularjs wygląda następująco.
adminControllers.controller('LoginController', ['$scope', '$http', 'AdminService', function($scope, $http, AdminService) {
$scope.username = '';
$scope.password = '';
$scope.signIn = function() {
AdminService.login($scope.username, $scope.password)
.success(function(d,s) {
if(d['success']) {
console.log('ok authenticated, call another REST endpoint');
AdminService.isAdminLoggedIn()
.success(function(d,s) {
console.log('i can access a protected REST endpoint after logging in');
})
.error(function(d, s) {
console.log('huh, error checking to see if admin is logged in');
$scope.reset();
});
} else {
console.log('bad credentials?');
}
})
.error(function(d, s) {
console.log('huh, error happened!');
});
};
}]);
Podczas rozmowy telefonicznej http://localhost:8080/api/admin/isloggedin
otrzymuję 401 Unauthorized
.
Po stronie aplikacji REST mam filtr CORS, który wygląda następująco.
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
@Override
public void destroy() { }
@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", "http://localhost:50029");
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, X-Auth-Token");
response.setHeader("Access-Control-Allow-Credentials", "true");
if(!"OPTIONS".equalsIgnoreCase(request.getMethod())) {
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig config) throws ServletException { }
}
Moja wiosenna konfiguracja zabezpieczeń wygląda następująco.
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private JsonAuthSuccessHandler jsonAuthSuccessHandler;
@Autowired
private JsonAuthFailureHandler jsonAuthFailureHandler;
@Autowired
private JsonLogoutSuccessHandler jsonLogoutSuccessHandler;
@Autowired
private AuthenticationProvider authenticationProvider;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PersistentTokenRepository persistentTokenRepository;
@Value("${rememberme.key}")
private String rememberMeKey;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.authorizeRequests()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/", "/admin", "/css/**", "/js/**", "/fonts/**", "/api/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(jsonAuthSuccessHandler)
.failureHandler(jsonAuthFailureHandler)
.permitAll()
.and()
.logout()
.deleteCookies("remember-me", "JSESSIONID")
.logoutSuccessHandler(jsonLogoutSuccessHandler)
.permitAll()
.and()
.rememberMe()
.userDetailsService(userDetailsService)
.tokenRepository(persistentTokenRepository)
.rememberMeCookieName("REMEMBER_ME")
.rememberMeParameter("remember_me")
.tokenValiditySeconds(1209600)
.useSecureCookie(false)
.key(rememberMeKey);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
}
Wszystko, co robią programy obsługi, to wypisywanie odpowiedzi JSON, na przykład {success: true}
na podstawie tego, czy użytkownik zalogował się, nie uwierzytelnił się lub wylogował. Do RestAuthenticationEntryPoint
wygląda następująco.
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest req, HttpServletResponse resp, AuthenticationException ex)
throws IOException, ServletException {
resp.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
Jakieś pomysły na temat tego, czego mi brakuje lub co robię źle?
źródło
API Gateway
chmury wiosennej, co uważałem za przesadę .Odpowiedzi:
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class SimpleCORSFilter implements Filter { private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class); public SimpleCORSFilter() { log.info("SimpleCORSFilter init"); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me"); chain.doFilter(req, res); } @Override public void init(FilterConfig filterConfig) { } @Override public void destroy() { } }
Nie ma potrzeby dodatkowego definiowania tego filtru, wystarczy dodać tę klasę. Wiosna zostanie zeskanowana i doda ją za Ciebie. SimpleCORSFilter. Oto przykład: przyciski włączania sprężyny
źródło
HEADERS
iX_REDIRECT_LOCATION_HEADER
? 2) Czy wierszrequest.getRequestURL());
jest literówką lub błędem kopiowania / wklejania? 3) Dlaczego nie sprawdzaszOPTIONS
i nie kontynuujesz pracy z łańcuchem filtrów?request.getHeader("Origin")
jak pokazano powyżej z powodu podziału odpowiedzi HTTP@Order(Ordered.HIGHEST_PRECEDENCE)
.Byłem w podobnej sytuacji. Po przeprowadzeniu badań i testów, oto moje ustalenia:
W przypadku Spring Boot zalecanym sposobem włączenia globalnego CORS jest zadeklarowanie w Spring MVC i połączenie z drobnoziarnistą
@CrossOrigin
konfiguracją jako:@Configuration public class CorsConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*") .allowedHeaders("*"); } }; } }
Teraz, ponieważ używasz Spring Security, musisz włączyć CORS również na poziomie Spring Security, aby umożliwić mu wykorzystanie konfiguracji zdefiniowanej na poziomie Spring MVC jako:
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and()... } }
Oto bardzo doskonały tutorial wyjaśniający obsługę CORS we frameworku Spring MVC.
źródło
Jeśli chcesz włączyć CORS bez używania filtrów lub bez pliku konfiguracyjnego, po prostu dodaj
@CrossOrigin
na górę kontrolera i działa.
źródło
Aby zbudować na innych odpowiedziach powyżej, w przypadku, gdy masz aplikację usługi Spring boot REST (nie Spring MVC) z zabezpieczeniami Spring, wystarczy
WebMvcConfigurer
włączyć CORS za pomocą zabezpieczeń Spring (jeśli używasz Spring MVC, użycie fasoli, jak wspomniał Yogen, może być sposób postępowania, ponieważ zabezpieczenia Spring zostaną przekazane do wspomnianej tam definicji CORS)Musisz więc mieć konfigurację zabezpieczeń, która wykonuje następujące czynności:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //other http security config http.cors().configurationSource(corsConfigurationSource()); } //This can be customized as required CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); List<String> allowOrigins = Arrays.asList("*"); configuration.setAllowedOrigins(allowOrigins); configuration.setAllowedMethods(singletonList("*")); configuration.setAllowedHeaders(singletonList("*")); //in case authentication is enabled this flag MUST be set, otherwise CORS requests will fail configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; }
}
Ten link zawiera więcej informacji na ten temat: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors
Uwaga:
UserDetailsService
na przykład za pomocą ),configuration.setAllowCredentials(true);
należy dodaćPrzetestowano pod kątem Spring boot 2.0.0.RELEASE (tj. Spring 5.0.4.RELEASE i Spring security 5.0.3.RELEASE)
źródło
Używam
spring boot 2.1.0
i to, co zadziałało, toA. Dodaj mapowania korsów według:
@Configuration public class Config implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("*"); } }
B. Dodaj poniższą konfigurację do mojej
HttpSecurity
dla zabezpieczenia wiosennego.cors().configurationSource(new CorsConfigurationSource() { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration config = new CorsConfiguration(); config.setAllowedHeaders(Collections.singletonList("*")); config.setAllowedMethods(Collections.singletonList("*")); config.addAllowedOrigin("*"); config.setAllowCredentials(true); return config; } })
Również w przypadku serwera proxy Zuul możesz użyć tego ZAMIAST A i B (po prostu użyj,
HttpSecurity.cors()
aby włączyć go w zabezpieczeniach Spring):@Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); final CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.addAllowedMethod("OPTIONS"); config.addAllowedMethod("HEAD"); config.addAllowedMethod("GET"); config.addAllowedMethod("PUT"); config.addAllowedMethod("POST"); config.addAllowedMethod("DELETE"); config.addAllowedMethod("PATCH"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); }
źródło
org.springframework.web.filter.CorsFilter
. Miałem ten sam problem, gdy przypadkowo użyłem go z paczek Catalina.To działa dla mnie:
@Configuration public class MyConfig extends WebSecurityConfigurerAdapter { //... @Override protected void configure(HttpSecurity http) throws Exception { //... http.cors().configurationSource(new CorsConfigurationSource() { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration config = new CorsConfiguration(); config.setAllowedHeaders(Collections.singletonList("*")); config.setAllowedMethods(Collections.singletonList("*")); config.addAllowedOrigin("*"); config.setAllowCredentials(true); return config; } }); //... } //... }
źródło
Dla mnie jedyną rzeczą, która zadziałała w 100%, gdy zastosowano zabezpieczenia wiosenne, było pominięcie całego dodatkowego puchu dodatkowych filtrów i fasoli oraz jakiejkolwiek pośredniej „magii”, którą ludzie sugerowali, że działa dla nich, ale nie dla mnie.
Zamiast tego po prostu wymuś napisanie potrzebnych nagłówków za pomocą zwykłego
StaticHeadersWriter
:@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // your security config here .authorizeRequests() .antMatchers(HttpMethod.TRACE, "/**").denyAll() .antMatchers("/admin/**").authenticated() .anyRequest().permitAll() .and().httpBasic() .and().headers().frameOptions().disable() .and().csrf().disable() .headers() // the headers you want here. This solved all my CORS problems! .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Origin", "*")) .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Methods", "POST, GET")) .addHeaderWriter(new StaticHeadersWriter("Access-Control-Max-Age", "3600")) .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Credentials", "true")) .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Headers", "Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization")); } }
To najbardziej bezpośredni i wyraźny sposób, w jaki to robię. Mam nadzieję, że to komuś pomoże.
źródło
Krok 1
Dodanie adnotacji do kontrolera z
@CrossOrigin
adnotacją pozwoli na konfiguracje CORS.@CrossOrigin @RestController public class SampleController { ..... }
Krok 2
Spring ma już CorsFilter, mimo że możesz po prostu zarejestrować swój własny CorsFilter jako ziarno, aby zapewnić własną konfigurację w następujący sposób.
@Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); final CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); // Provide list of origins if you want multiple origins config.setAllowedHeaders(Arrays.asList("Origin", "Content-Type", "Accept")); config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH")); config.setAllowCredentials(true); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); }
źródło
Sprawdź ten:
@Override protected void configure(HttpSecurity httpSecurity) throws Exception { ... .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() ... }
źródło
Rozszerzenie klasy WebSecurityConfigurerAdapter i przesłanianie metody configure () w klasie @EnableWebSecurity zadziałałoby: Poniżej znajduje się przykładowa klasa
@Override protected void configure(final HttpSecurity http) throws Exception { http .csrf().disable() .exceptionHandling(); http.headers().cacheControl(); @Override public CorsConfiguration getCorsConfiguration(final HttpServletRequest request) { return new CorsConfiguration().applyPermitDefaultValues(); } }); } }
źródło
Jeśli pierwotnie twój program nie używa zabezpieczeń Spring i nie stać go na zmianę kodu, utworzenie prostego odwrotnego proxy może załatwić sprawę. W moim przypadku użyłem Nginx z następującą konfiguracją:
http { server { listen 9090; location / { if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; # # Custom headers and headers various browsers *should* be OK with but aren't # add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; # # Tell client that this pre-flight info is valid for 20 days # add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } if ($request_method = 'POST') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } if ($request_method = 'GET') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; } proxy_pass http://localhost:8080; } } }
Mój program słucha : 8080 .
ODNIESIENIE: CORS na Nginx
źródło
To właśnie zadziałało dla mnie.
@EnableWebSecurity public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors(); } } @Configuration public class WebConfiguration implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry .addMapping("/**") .allowedMethods("*") .allowedHeaders("*") .allowedOrigins("*") .allowCredentials(true); } }
źródło
Ta odpowiedź kopiuje odpowiedź @abosancic, ale zapewnia dodatkowe bezpieczeństwo, aby uniknąć exploita CORS .
Wskazówka 1: Nie odzwierciedlaj przychodzącego źródła bez sprawdzenia listy dozwolonych hostów, do których można uzyskać dostęp.
Wskazówka 2: Zezwalaj na żądania poświadczeń tylko w przypadku hostów z białej listy.
import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class SimpleCORSFilter implements Filter { private final Logger log = LoggerFactory.getLogger(SimpleCORSFilter.class); private List<String> allowedOrigins; public SimpleCORSFilter() { log.info("SimpleCORSFilter init"); allowedOrigins = new ArrayList<>(); allowedOrigins.add("https://mysafeorigin.com"); allowedOrigins.add("https://itrustthissite.com"); } @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String allowedOrigin = getOriginToAllow(request.getHeader("Origin")); if(allowedOrigin != null) { response.setHeader("Access-Control-Allow-Origin", allowedOrigin); response.setHeader("Access-Control-Allow-Credentials", "true"); } response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me"); chain.doFilter(req, res); } @Override public void init(FilterConfig filterConfig) { } @Override public void destroy() { } public String getOriginToAllow(String incomingOrigin) { if(allowedOrigins.contains(incomingOrigin.toLowerCase())) { return incomingOrigin; } else { return null; } } }
źródło
W naszej aplikacji Spring Boot skonfigurowaliśmy CorsConfigurationSource w ten sposób.
Sekwencja dodawania,
allowedOrigns
a następnie ustawiania,applyPermitDefaultValues()
pozwala Springowi ustawić domyślne wartości dla dozwolonych nagłówków, ujawnionych nagłówków, dozwolonych metod itp., Więc nie musimy ich określać.public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("http://localhost:8084")); configuration.applyPermitDefaultValues(); UrlBasedCorsConfigurationSource configurationSource = new UrlBasedCorsConfigurationSource(); configurationSource.registerCorsConfiguration("/**", configuration); return configurationSource; }
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/api/**") .access("@authProvider.validateApiKey(request)") .anyRequest().authenticated() .and().cors() .and().csrf().disable() .httpBasic().authenticationEntryPoint(authenticationEntryPoint); http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); }
źródło
Po prostu utwórz jedną klasę , wszystko będzie dobrze z tym:
@Component @Order(Ordered.HIGHEST_PRECEDENCE) public class MyCorsConfig implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { final HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, enctype"); response.setHeader("Access-Control-Max-Age", "3600"); if (HttpMethod.OPTIONS.name().equalsIgnoreCase(((HttpServletRequest) req).getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } @Override public void destroy() { } @Override public void init(FilterConfig config) throws ServletException { } }
źródło
To właśnie zadziałało w moim przypadku, aby wyłączyć CORS między uruchomieniem Spring i React
@Configuration public class CorsConfig implements WebMvcConfigurer { /** * Overriding the CORS configuration to exposed required header for ussd to work * * @param registry CorsRegistry */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .allowedHeaders("*") .allowCredentials(true) .maxAge(4800); } }
Musiałem zmodyfikować konfigurację zabezpieczeń również jak poniżej:
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .cors().configurationSource(new CorsConfigurationSource() { @Override public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { CorsConfiguration config = new CorsConfiguration(); config.setAllowedHeaders(Collections.singletonList("*")); config.setAllowedMethods(Collections.singletonList("*")); config.addAllowedOrigin("*"); config.setAllowCredentials(true); return config; } }).and() .antMatcher("/api/**") .authorizeRequests() .anyRequest().authenticated() .and().httpBasic() .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and().exceptionHandling().accessDeniedHandler(apiAccessDeniedHandler()); }
źródło