Мы создаем в Spring загрузочный API отдыха, который должен взаимодействовать с веб-сайтом. Веб-сайт должен быть единственным потребителем наших конечных точек. Для этого Веб-сайт должен аутентифицировать себя через clientId & clientSecret при каждом запросе.
Это наш AuthorizationServerConfig:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer.inMemory().withClient("myClientId").secret(passwordEncoder.encode("test123"))
.accessTokenValiditySeconds(600)
.refreshTokenValiditySeconds(2592000)
.authorizedGrantTypes(authorizedGrantTypes).scopes("read", "write").resourceIds("users");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).authenticationManager(authenticationManager);
}
.
.
.
}
А это WebSecurityConfig
@Order(1)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
public void configure(WebSecurity web) throws Exception {
web.debug(true);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/users/pre-register").authenticated()
.and().authorizeRequests()
.antMatchers(HttpMethod.POST, "/oauth/token").authenticated()
.and().authorizeRequests().anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encoder());
}
@Bean
public BCryptPasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
}
У нас есть 2 конечные точки / пользователи / предварительная регистрация и / oauth / токен
Для вызова конечной точки / пользователи / предварительная регистрация необходимы только правильный clientId и clientSecret. Для вызова конечной точки / oauth / token необходимы правильный clientId и clientSecret и уже зарегистрированный пользователь + пароль.
Конечная точка / oauth / token работает как задумано. Если вы предоставите правильные учетные данные, вы получите токен в ответ.
Если вы отправите ложный clientSecret, вы получите эту ошибку.
<!doctype html>
<html lang="en">
<head>
<title>HTTP Status 401 – Unauthorized</title>
</head>
<body>
<h1>HTTP Status 401 – Unauthorized</h1>
<hr class="line" />
<p><b>Type</b> Status Report</p>
<p><b>Message</b> Unauthorized</p>
<p><b>Description</b> The request has not been applied because it lacks valid authentication credentials for the
target resource.</p>
<hr class="line" />
<h3>Apache Tomcat/9.0.14</h3>
</body>
</html>
Если вы отправите ложный пароль для зарегистрированного пользователя Вы получаете эту ошибку.
{
"error": "invalid_grant",
"error_description": "Bad credentials"
}
Таким образом, кажется, что все в порядке с Endpoint /oauth/token.
Конечная точка / users / pre-register с другой стороны не работает должным образом .
Это мой запрос:
POST /users/pre-register HTTP/1.1
Host: localhost:8080
Content-Type: application/json
Authorization: Basic bXlDbGllbnRJZDp0ZXN0MTIz
{
"email":"harryHirsch@myCompany.de",
"password":"Test1234"
}
Это ошибка, которую я получаю:
<html lang="en">
<head>
<title>HTTP Status 403 – Forbidden</title>
</head>
<body>
<h1>HTTP Status 403 – Forbidden</h1>
<hr class="line" />
<p><b>Type</b> Status Report</p>
<p><b>Message</b> Access Denied</p>
<p><b>Description</b> The server understood the request but refuses to authorize it.</p>
<hr class="line" />
<h3>Apache Tomcat/9.0.14</h3>
</body>
</html>
Thid ошибка, которую я вижу в моих лог-файлах:
[2020-01-20T15:43:40.040Z] [org.springframework.security.web.FilterChainProxy$VirtualFilterChain] [http-nio-8080-exec-2] [328] [DEBUG] /users/pre-register at position 10 of 11 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
[2020-01-20T15:43:40.040Z] [org.springframework.security.web.FilterChainProxy$VirtualFilterChain] [http-nio-8080-exec-2] [328] [DEBUG] /users/pre-register at position 11 of 11 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
[2020-01-20T15:43:40.040Z] [org.springframework.security.web.util.matcher.AntPathRequestMatcher] [http-nio-8080-exec-2] [176] [DEBUG] Checking match of request : '/users/pre-register'; against '/users/pre-register'
[2020-01-20T15:43:40.040Z] [org.springframework.security.access.intercept.AbstractSecurityInterceptor] [http-nio-8080-exec-2] [219] [DEBUG] Secure object: FilterInvocation: URL: /users/pre-register; Attributes: [authenticated]
[2020-01-20T15:43:40.040Z] [org.springframework.security.access.intercept.AbstractSecurityInterceptor] [http-nio-8080-exec-2] [348] [DEBUG] Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@55041127: 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
[2020-01-20T15:43:40.040Z] [org.springframework.security.access.vote.AffirmativeBased] [http-nio-8080-exec-2] [66] [DEBUG] Voter: org.springframework.security.web.access.expression.WebExpressionVoter@31411a9b, returned: -1
[2020-01-20T15:43:40.040Z] [org.springframework.security.web.access.ExceptionTranslationFilter] [http-nio-8080-exec-2] [181] [DEBUG] Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119) ~[spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.3.RELEASE.jar:5.1.3.RELEASE]
Я подозреваю, что моя ошибка лежит в методе configure для http моего AuthneticationManager
.
.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors()
.and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/users/pre-register").authenticated()
.and().authorizeRequests()
.antMatchers(HttpMethod.POST, "/oauth/token").authenticated()
.and().authorizeRequests().anyRequest().authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
.
.
Но я не уверен в этом. Любая помощь очень ценится!
PS Кто-нибудь знает хороший сайт, где подробно описаны antMatchers и как они правильно настроены?
РЕДАКТИРОВАТЬ: Я мог бы сузить ошибку немного вниз. В конечной точке / oauth / token, которая работает как задумано, Веб-сайт, использующий наш API, должен аутентифицировать себя через clientId + clientSecret (определенный в нашем AuthorizationServerConfig). А затем проверяются учетные данные пользователя, если они имеют git. Имя пользователя и его пароль (хэшированные через bcrypt) хранятся в нашей БД.
В конечной точке / пользователи / предварительно зарегистрируйте предоставленные учетные данные из моего запроса
.
Authorization: Basic bXlDbGllbnRJZDp0ZXN0MTIz
.
, которые не проверяются сравнивая его с clientID и clientSecret, я определил в моем AuthorizationServerConfig. Но вместо этого приложение пытается проверить учетные данные путем поиска пользователя в нашей БД. Это явно неправильно.