изменила название папки и убрала лишние импорты

This commit is contained in:
Elena Ponomareva
2026-05-07 08:01:24 +03:00
parent 6158d3543c
commit 0aa7dcaf98
9 changed files with 2 additions and 2 deletions
@@ -0,0 +1,86 @@
package com.project.movienight.adapters.security
import com.project.movienight.adapters.persistence.entity.toDomain
import com.project.movienight.adapters.persistence.entity.toEntity
import com.project.movienight.application.ports.input.security.OAuth2UserInfo
import com.project.movienight.application.ports.output.IdGenerator
import com.project.movienight.application.ports.output.UserRepositoryPort
import com.project.movienight.domain.model.AuthProvider
import com.project.movienight.domain.model.User
import org.slf4j.LoggerFactory
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest
import org.springframework.security.oauth2.core.OAuth2AuthenticationException
import org.springframework.security.oauth2.core.user.OAuth2User
import org.springframework.stereotype.Service
@Service
class CustomOAuth2UserService(
private val userRepository: UserRepositoryPort,
private val idGenerator: IdGenerator,
) : DefaultOAuth2UserService() {
companion object {
private val log = LoggerFactory.getLogger(CustomOAuth2UserService::class.java)
}
override fun loadUser(userRequest: OAuth2UserRequest): OAuth2User {
val oAuth2User = super.loadUser(userRequest)
val registrationId = userRequest.clientRegistration.registrationId
log.debug("Processing OAuth2 login for provider: {}", registrationId)
return try {
val userInfo = OAuth2UserInfoFactory.getOAuth2UserInfo(registrationId, oAuth2User)
val user = findOrCreateUser(userInfo)
UserPrincipal.create(user, oAuth2User.attributes)
} catch (e: IllegalArgumentException) {
log.error("OAuth2 authentication failed: ${e.message}", e)
throw OAuth2AuthenticationException("Failed to process OAuth2 user data")
} catch (e: OAuth2AuthenticationException) {
log.error("OAuth2 authentication failed: ${e.message}", e)
throw e
}
}
private fun findOrCreateUser(userInfo: OAuth2UserInfo): User {
val provider = AuthProvider.valueOf(userInfo.getProvider().uppercase())
val existingUser =
userRepository.findByProviderAndProviderId(
provider,
userInfo.getProviderId(),
)
return if (existingUser != null) {
log.debug("User found by provider: {}", userInfo.getProvider())
existingUser
} else {
val userByEmail = userRepository.findByEmail(userInfo.getEmail())
if (userByEmail != null) {
log.debug("Linking OAuth2 account to existing user: {}", userInfo.getEmail())
val entity =
userByEmail.toEntity(
provider = provider,
providerId = userInfo.getProviderId(),
)
userRepository.save(entity.toDomain())
} else {
log.debug("Creating new user for provider: {}", userInfo.getProvider())
val newUser =
User(
id = idGenerator.generateId(),
name = userInfo.getName(),
email = userInfo.getEmail(),
library = null,
)
val entity =
newUser.toEntity(
provider = provider,
providerId = userInfo.getProviderId(),
)
userRepository.save(entity.toDomain())
}
}
}
}
@@ -0,0 +1,17 @@
package com.project.movienight.adapters.security
import com.project.movienight.application.ports.input.security.OAuth2UserInfo
class GoogleOAuth2UserInfo(
private val attributes: Map<String, Any>,
) : OAuth2UserInfo {
override fun getProviderId(): String = attributes["sub"] as String
override fun getEmail(): String = attributes["email"] as String
override fun getName(): String = attributes["name"] as String
override fun getProvider(): String = "google"
override fun getAttributes(): Map<String, Any> = attributes
}
@@ -0,0 +1,21 @@
package com.project.movienight.adapters.security
import com.project.movienight.application.ports.input.security.OAuth2UserInfo
import org.springframework.security.oauth2.core.OAuth2AuthenticationException
import org.springframework.security.oauth2.core.user.OAuth2User
object OAuth2UserInfoFactory {
fun getOAuth2UserInfo(
registrationId: String,
user: OAuth2User,
): OAuth2UserInfo {
val attributes = user.attributes
return when (registrationId.lowercase()) {
"google" -> GoogleOAuth2UserInfo(attributes)
"yandex" -> YandexOAuth2UserInfo(attributes)
"vk" -> VkOAuth2UserInfo(attributes)
else -> throw OAuth2AuthenticationException("Unknown provider: $registrationId")
}
}
}
@@ -0,0 +1,42 @@
package com.project.movienight.adapters.security
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.web.SecurityFilterChain
@Configuration
@EnableWebSecurity
class SecurityConfiguration(
private val customOAuth2UserService: CustomOAuth2UserService,
) {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http
.oauth2Login { oauth2 ->
oauth2
.userInfoEndpoint { userInfo ->
userInfo.userService(customOAuth2UserService)
}
.defaultSuccessUrl("/api/users/me", true)
}
.authorizeHttpRequests { auth ->
auth
.requestMatchers("/", "/login/**", "/oauth2/**", "/h2-console/**", "/actuator/health").permitAll()
.requestMatchers("/api/users/me").authenticated()
.requestMatchers("/api/**").authenticated()
.anyRequest().authenticated()
}
.headers { headers ->
headers.frameOptions { frameOptions ->
frameOptions.sameOrigin()
}
}
.csrf { csrf ->
csrf.disable()
}
return http.build()
}
}
@@ -0,0 +1,40 @@
package com.project.movienight.adapters.security
import com.project.movienight.domain.model.User
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.oauth2.core.user.OAuth2User
import java.util.UUID
class UserPrincipal(
private val user: User,
private val attributes: Map<String, Any>? = null,
) : OAuth2User, UserDetails {
fun getId(): UUID = user.id
override fun getName(): String = user.name
override fun getAttributes(): Map<String, Any> = attributes ?: emptyMap()
override fun getAuthorities(): Collection<GrantedAuthority> =
listOf(SimpleGrantedAuthority("ROLE_USER"))
override fun getPassword(): String = ""
override fun getUsername(): String = user.email
override fun isAccountNonExpired(): Boolean = true
override fun isAccountNonLocked(): Boolean = true
override fun isCredentialsNonExpired(): Boolean = true
override fun isEnabled(): Boolean = true
companion object {
fun create(user: User, attributes: Map<String, Any>? = null): UserPrincipal =
UserPrincipal(user, attributes)
}
}
@@ -0,0 +1,28 @@
package com.project.movienight.adapters.security
import com.project.movienight.application.ports.input.security.OAuth2UserInfo
class VkOAuth2UserInfo(
private val attributes: Map<String, Any>,
) : OAuth2UserInfo {
override fun getProviderId(): String =
(attributes["response"] as? List<*>)
?.firstOrNull()
?.let { it as? Map<*, *> }
?.get("id")
?.toString() ?: ""
override fun getEmail(): String = attributes["email"]?.toString() ?: ""
override fun getName(): String {
val response = attributes["response"] as? List<*>
val first = response?.firstOrNull() as? Map<*, *>
val firstName = first?.get("first_name")?.toString() ?: ""
val lastName = first?.get("last_name")?.toString() ?: ""
return "$firstName $lastName".trim()
}
override fun getProvider(): String = "vk"
override fun getAttributes(): Map<String, Any> = attributes
}
@@ -0,0 +1,22 @@
package com.project.movienight.adapters.security
import com.project.movienight.application.ports.input.security.OAuth2UserInfo
class YandexOAuth2UserInfo(
private val attributes: Map<String, Any>,
) : OAuth2UserInfo {
override fun getProviderId(): String = attributes["id"]?.toString() ?: ""
override fun getEmail(): String =
(attributes["emails"] as? List<*>)
?.firstOrNull()
?.let { it as? Map<*, *> }
?.get("value")
?.toString() ?: ""
override fun getName(): String = attributes["display_name"]?.toString() ?: ""
override fun getProvider(): String = "yandex"
override fun getAttributes(): Map<String, Any> = attributes
}