Я сейчас работаю над проектом, используя Spring Boot и OAuth2 для аутентификации, и я новичок ie здесь. Я разделил сервер аутентификации (AS) и сервер ресурсов (RS) на два разных приложения, работающих на двух разных портах. У меня также есть клиентское приложение, работающее на другом порту, и я попытаюсь получить токен доступа от AS. Проблема в том, что, когда я обращаюсь к клиентскому приложению для аутентификации, оно перенаправляет меня в AS для аутентификации, а после ввода имени пользователя и пароля оно перенаправляет меня обратно в клиентское приложение. Так или иначе, он застревает на этом шаге, когда формирует al oop. Посмотрите на сетевой трафик c.
Затем я смотрю на консоль клиентского приложения, и она показывает this
Я провел исследование Inte rnet и, похоже, проблема в RS. Ниже приведены мои настройки как на AS, так и на RS. Также клиентское приложение.
Сервер аутентификации:
AuthenticationServerConfig. java
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Value("${jwt.certificate.store.file}")
private Resource keystore;
@Value("${jwt.certificate.store.password}")
private String keystorePassword;
@Value("${jwt.certificate.key.alias}")
private String keyAlias;
@Value("${jwt.certificate.key.password}")
private String keyPassword;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private ClientDetailsService clientDetails;
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(
keystore, keystorePassword.toCharArray());
KeyPair keyPair = keyStoreKeyFactory.getKeyPair(
keyAlias, keyPassword.toCharArray());
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyPair);
return converter;
}
@Override
public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception{
clientDetailsServiceConfigurer.withClientDetails(clientDetails);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.accessTokenConverter(jwtAccessTokenConverter())
.userDetailsService(userDetailsService);
}
}
WebSecurityConfig. java
@EnableWebSecurity
@EnableOAuth2Client
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Bean
public AuthenticationProvider authenticationProvider(){
return new CustomDAOAuthenticationProvider(userDetailsService, passwordEncoder);
}
@Bean
public GrantedAuthoritiesMapper grantedAuthoritiesMapper() {
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
simpleAuthorityMapper.setPrefix("ROLE_");
simpleAuthorityMapper.setConvertToUpperCase(true);
return simpleAuthorityMapper;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.authenticationProvider(authenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()
.authorizeRequests()
.antMatchers( "/css/**", "/images/**", "/api/me").permitAll()
.anyRequest().authenticated()
.and().formLogin().loginPage("/login").permitAll()
.defaultSuccessUrl("/api/me")
.and().logout().logoutSuccessUrl("/login");
}
}
appilication. yml
server:
port: 7000
servlet:
context-path: /e-auth
spring:
datasource:
url: jdbc:mysql://localhost:3306/e_auth
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: false
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
enable_lazy_load_no_trans: true
jwt:
certificate:
store:
file: classpath:/certificate/jwt.jks
password: password
key:
alias: jwt
password: password
Сервер ресурсов:
ResourceServerConfig. java
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Qualifier("jwtTokenStore")
@Autowired
TokenStore tokenStore;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and().exceptionHandling()
.authenticationEntryPoint((httpServletRequest, httpServletResponse, authException)
-> httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.accessDeniedHandler((httpServletRequest, httpServletResponse, authException)
-> httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED));
}
public void configure(ResourceServerSecurityConfigurer resource){
resource.tokenStore(tokenStore)
.resourceId("USER_ADMIN_RESOURCE");
}
}
ResoucreController. java
@RestController
@RequestMapping("/api")
public class ResourcesController {
@GetMapping("/user")
public Object returnPrincipal(Principal user){
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
application.yml
server:
port: 7003
servlet:
context-path: /e-resrc
spring:
datasource:
url: jdbc:mysql://localhost:3306/e_data
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
show-sql: false
hibernate:
ddl-auto: update
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
enable_lazy_load_no_trans: true
security:
oauth2:
resource:
jwt:
keyValue: |
-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
Клиентское приложение:
WebSecurityConfig. java
@Configuration
@EnableOAuth2Sso
@Order(0)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/**")
.authorizeRequests()
.antMatchers("/login**").permitAll()
.anyRequest().authenticated()
.and().httpBasic();
}
}
application.yml
server:
port: 7002
servlet:
context-path: /e-connect
security:
oauth2:
client:
access-token-uri: http://localhost:7000/e-auth/oauth/token
user-authorization-uri: http://localhost:7000/e-auth/oauth/authorize
client-id: app
client-secret: password
resource:
user-info-uri: http://localhost:7003/e-resrc/api/user
Подводя итог: я получаю следующее сообщение от консоли клиентского приложения и AS не выдает токен доступа для клиентского приложения.
WARN 12820 --- [nio-7002-exec-9] o.s.b.a.s.o.r.UserInfoTokenServices: Could not fetch user details: class org.springframework.security.oauth2.common.exceptions.InvalidRequestException,
Possible CSRF detected - state parameter was required but no state could be found
Также я смог использовать Postman для получения токена доступа от AS с потоком authorization_code. Дополнительный код можно найти в моем хранилище на GitHub: https://github.com/augustus981/E-Connect
Пожалуйста, помогите мне с этим. Я застрял на этой неделе и не знаю, как это исправить.
ОБНОВЛЕНИЕ 1:
Я настроил клиентское приложение следующим образом, чтобы увидеть что там происходит, и вещи go довольно странные. Когда клиентское приложение впервые отправляет идентификатор клиента, redirectURI, тип ответа и состояние в AS.
http://localhost:7000/e-auth/oauth/authorize?client_id=app&redirect_uri=http://localhost:7002/e-connect/login&response_type=code&state=z3WDTJ
Затем AS перенаправляет обратно на redirectURI с кодом и точным состоянием, клиентское приложение сообщает, что оно не авторизовано (401). Это URI перенаправления, которое клиентское приложение сообщает, что оно неавторизовано. Я понятия не имею, что происходит.
http://localhost:7002/e-connect/login?code=SiHmGB&state=z3WDTJ
Поэтому я разрешаю все подключения к "/ login **", но тем не менее оно не авторизовано.
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login**", "/error**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and().httpBasic();
}