mirror of
https://github.com/LOBSTERVOVA/Tennis-Site.git
synced 2026-04-17 17:40:49 +03:00
Настроил и исправил авторизацию
This commit is contained in:
5
pom.xml
5
pom.xml
@@ -138,6 +138,11 @@
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.11.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
<version>2.20.1</version> <!-- или актуальная версия -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
|
||||
@@ -12,16 +12,10 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.ReactiveAuthenticationManager;
|
||||
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
|
||||
import org.springframework.security.config.Customizer;
|
||||
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
|
||||
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
|
||||
import org.springframework.security.config.web.server.ServerHttpSecurity;
|
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsPasswordService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain;
|
||||
@@ -30,8 +24,7 @@ import org.springframework.security.web.server.csrf.CookieServerCsrfTokenReposit
|
||||
import org.springframework.security.web.server.csrf.ServerCsrfTokenRequestAttributeHandler;
|
||||
import org.springframework.security.web.server.savedrequest.ServerRequestCache;
|
||||
import org.springframework.security.web.server.savedrequest.WebSessionServerRequestCache;
|
||||
import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@Slf4j
|
||||
@@ -40,31 +33,10 @@ import java.net.URI;
|
||||
@RequiredArgsConstructor
|
||||
@EnableReactiveMethodSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
private final AppUserRepository userRepository;
|
||||
private final JwtService jwtService;
|
||||
|
||||
// Цепочка для API (Basic Auth) - CSRF отключаем
|
||||
@Bean
|
||||
@Order(1)
|
||||
public SecurityWebFilterChain apiFilterChain(ServerHttpSecurity http) {
|
||||
return http
|
||||
.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/api/**"))
|
||||
.authorizeExchange(exchange -> exchange
|
||||
.pathMatchers("/api/mobile/login").permitAll()
|
||||
.anyExchange().authenticated()
|
||||
)
|
||||
.httpBasic(Customizer.withDefaults())
|
||||
.formLogin(ServerHttpSecurity.FormLoginSpec::disable)
|
||||
.csrf(ServerHttpSecurity.CsrfSpec::disable) // CSRF отключаем для API
|
||||
.authenticationManager(reactiveAuthenticationManager())
|
||||
.build();
|
||||
}
|
||||
|
||||
// Цепочка для веб-интерфейса (Form Login) - CSRF включаем
|
||||
@Bean
|
||||
@Order(2)
|
||||
public SecurityWebFilterChain webFilterChain(ServerHttpSecurity http) {
|
||||
public SecurityWebFilterChain filterChain(ServerHttpSecurity http){
|
||||
ServerCsrfTokenRequestAttributeHandler requestHandler = new ServerCsrfTokenRequestAttributeHandler();
|
||||
requestHandler.setTokenFromMultipartDataEnabled(true);
|
||||
|
||||
@@ -74,13 +46,13 @@ public class SecurityConfig {
|
||||
ErrorHandlingFilter errorHandlingFilter = new ErrorHandlingFilter();
|
||||
|
||||
return http
|
||||
.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/account/**"))
|
||||
.csrf(csrf -> csrf.csrfTokenRequestHandler(requestHandler).csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
|
||||
.addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
|
||||
.addFilterAfter(errorHandlingFilter, SecurityWebFiltersOrder.AUTHENTICATION)
|
||||
//.addFilterAfter(errorHandlingFilter, SecurityWebFiltersOrder.AUTHENTICATION)
|
||||
.authorizeExchange(exchange -> exchange
|
||||
.pathMatchers("/account/login").permitAll()
|
||||
.anyExchange().authenticated()
|
||||
.pathMatchers("/account/login","/error","/error/**").permitAll()
|
||||
.pathMatchers("/account/**").authenticated()
|
||||
.anyExchange().permitAll()
|
||||
)
|
||||
.formLogin(loginSpec -> loginSpec.loginPage("/account/login").authenticationSuccessHandler(authenticationSuccessHandler()))
|
||||
.logout(logoutSpec -> logoutSpec.logoutSuccessHandler(logoutSuccessHandler()))
|
||||
@@ -88,19 +60,6 @@ public class SecurityConfig {
|
||||
.build();
|
||||
}
|
||||
|
||||
// Цепочка для всех остальных путей (публичные)
|
||||
@Bean
|
||||
@Order(3)
|
||||
public SecurityWebFilterChain defaultFilterChain(ServerHttpSecurity http) {
|
||||
return http
|
||||
.securityMatcher(new PathPatternParserServerWebExchangeMatcher("/**"))
|
||||
.authorizeExchange(exchange -> exchange
|
||||
.anyExchange().permitAll()
|
||||
)
|
||||
.csrf(ServerHttpSecurity.CsrfSpec::disable)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServerRequestCache serverRequestCache() {
|
||||
return new WebSessionServerRequestCache();
|
||||
@@ -129,33 +88,12 @@ public class SecurityConfig {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ReactiveAuthenticationManager reactiveAuthenticationManager() {
|
||||
UserDetailsRepositoryReactiveAuthenticationManager manager = new UserDetailsRepositoryReactiveAuthenticationManager(userService());
|
||||
manager.setPasswordEncoder(passwordEncoder());
|
||||
manager.setUserDetailsPasswordService(userDetailsPasswordService());
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ReactiveUserDetailsPasswordService userDetailsPasswordService() {
|
||||
return new ReactiveUserDetailsPasswordService() {
|
||||
@Override
|
||||
public Mono<UserDetails> updatePassword(UserDetails user, String newPassword) {
|
||||
return userRepository.findByPhone(user.getUsername()).flatMap(appUser -> {
|
||||
appUser.setPassword(passwordEncoder().encode(newPassword));
|
||||
return userRepository.save(appUser);
|
||||
});
|
||||
}
|
||||
};
|
||||
public PasswordEncoder passwordEncoder(){
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public UserService userService(){
|
||||
return new UserService(userRepository,passwordEncoder());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder(){
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ public class JwtAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
//log.info("start auth manager");
|
||||
String accessToken = authentication.getPrincipal().toString();
|
||||
String refreshToken = authentication.getCredentials().toString();
|
||||
log.info("refresh is {},{}", accessToken, refreshToken);
|
||||
|
||||
if(jwt.validateToken(accessToken)){
|
||||
//log.info("access token is valid");
|
||||
@@ -105,7 +104,7 @@ public class JwtAuthenticationManager implements ReactiveAuthenticationManager {
|
||||
}
|
||||
|
||||
private Mono<Authentication> baseAuth(Authentication authentication){
|
||||
log.info("access and refresh token is not valid - try authenticate by basic login");
|
||||
//log.info("access and refresh token is not valid - try authenticate by basic login");
|
||||
String username = authentication.getPrincipal().toString();
|
||||
String password = authentication.getCredentials().toString();
|
||||
return userService.findByUsername(username).flatMap(user -> {
|
||||
|
||||
@@ -53,4 +53,4 @@ public class JwtAuthenticationSuccessHandler implements ServerAuthenticationSucc
|
||||
return webFilterExchange.getExchange().getResponse().setComplete();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ public class AppUser implements UserDetails {
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return this.phone;
|
||||
return getPhone();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -9,4 +9,5 @@ import java.util.UUID;
|
||||
public interface AppUserRepository extends R2dbcRepository<AppUser, UUID> {
|
||||
|
||||
Mono<AppUser> findByPhone(String phone);
|
||||
Mono<AppUser> findByUsername(String username);
|
||||
}
|
||||
|
||||
@@ -2,20 +2,22 @@ package com.example.dateplanner.services;
|
||||
|
||||
import com.example.dateplanner.repositories.AppUserRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class UserService implements ReactiveUserDetailsService {
|
||||
private final AppUserRepository appUserRepository;
|
||||
private final AppUserRepository userRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
public Mono<UserDetails> findByUsername(String username) {
|
||||
return appUserRepository.findByPhone(username).flatMap(Mono::just).cast(UserDetails.class);
|
||||
log.info("username {}", username);
|
||||
return userRepository.findByPhone(username).flatMap(Mono::just).cast(UserDetails.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public class CookieUtil {
|
||||
private final String SESSION;
|
||||
|
||||
protected CookieUtil(){
|
||||
String appName = "pstweb";
|
||||
String appName = "dp";
|
||||
REFRESH = appName + "-refresh";
|
||||
ACCESS = appName + "-access";
|
||||
SESSION = appName + "-session";
|
||||
|
||||
@@ -23,7 +23,7 @@ spring.flyway.locations=db/migration
|
||||
spring.flyway.validate-migration-naming=true
|
||||
spring.flyway.baseline-on-migrate=true
|
||||
#====================== minio configuration =====================
|
||||
minio.bucket=
|
||||
minio.bucket=${spring.application.name}
|
||||
minio.url=
|
||||
minio.cdn=
|
||||
minio.username=
|
||||
|
||||
@@ -103,13 +103,14 @@ function initHeader($header){
|
||||
<!-- Форма входа -->
|
||||
<div class="tab-pane fade show active" id="login" role="tabpanel">
|
||||
<form id="loginForm" method="POST" action="/account/login">
|
||||
<input type="hidden" name="_csrf" value="${csrf.token}"/>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Email или телефон</label>
|
||||
<input type="text" class="form-control" id="loginEmail" placeholder="example@mail.ru" required>
|
||||
<input type="text" class="form-control" id="loginEmail" placeholder="example@mail.ru" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Пароль</label>
|
||||
<input type="password" class="form-control" id="loginPassword" required>
|
||||
<input type="password" class="form-control" id="loginPassword" name="password" required>
|
||||
<div class="text-end mt-2">
|
||||
<a href="#" class="forgot-password" onclick="showForgotPassword()">Забыли пароль?</a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user