Files
TrisolarisServer/src/main/kotlin/com/android/trisolarisserver/controller/Auth.kt
androidlover5842 2c337b8709
All checks were successful
build-and-deploy / build-deploy (push) Successful in 27s
Return 401 for auth failures and log verify
2026-01-26 21:36:22 +05:30

100 lines
3.9 KiB
Kotlin

package com.android.trisolarisserver.controller
import com.android.trisolarisserver.controller.dto.PropertyUserResponse
import com.android.trisolarisserver.controller.dto.UserResponse
import com.android.trisolarisserver.repo.AppUserRepo
import com.android.trisolarisserver.repo.PropertyUserRepo
import com.android.trisolarisserver.security.MyPrincipal
import com.google.firebase.auth.FirebaseAuth
import jakarta.servlet.http.HttpServletRequest
import org.slf4j.LoggerFactory
import org.springframework.security.core.annotation.AuthenticationPrincipal
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ResponseStatusException
import org.springframework.http.HttpStatus
@RestController
@RequestMapping("/auth")
class Auth(
private val appUserRepo: AppUserRepo,
private val propertyUserRepo: PropertyUserRepo
) {
private val logger = LoggerFactory.getLogger(Auth::class.java)
@PostMapping("/verify")
fun verify(
@AuthenticationPrincipal principal: MyPrincipal?,
request: HttpServletRequest
): AuthResponse {
logger.info("Auth verify hit, principalPresent={}", principal != null)
return buildAuthResponse(principal ?: resolvePrincipalFromHeader(request))
}
@GetMapping("/me")
fun me(
@AuthenticationPrincipal principal: MyPrincipal?,
request: HttpServletRequest
): AuthResponse {
return buildAuthResponse(principal ?: resolvePrincipalFromHeader(request))
}
private fun buildAuthResponse(principal: MyPrincipal?): AuthResponse {
if (principal == null) {
throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Missing principal")
}
val user = appUserRepo.findById(principal.userId).orElseThrow {
ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found")
}
val memberships = propertyUserRepo.findByIdUserId(principal.userId).map {
PropertyUserResponse(
userId = it.id.userId!!,
propertyId = it.id.propertyId!!,
roles = it.roles.map { role -> role.name }.toSet()
)
}
return AuthResponse(
user = UserResponse(
id = user.id!!,
orgId = user.org.id!!,
firebaseUid = user.firebaseUid,
phoneE164 = user.phoneE164,
name = user.name,
disabled = user.disabled
),
properties = memberships
)
}
private fun resolvePrincipalFromHeader(request: HttpServletRequest): MyPrincipal {
val header = request.getHeader("Authorization") ?: throw ResponseStatusException(
HttpStatus.UNAUTHORIZED,
"Missing Authorization token"
)
if (!header.startsWith("Bearer ")) {
throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid Authorization header")
}
val token = header.removePrefix("Bearer ").trim()
val decoded = try {
FirebaseAuth.getInstance().verifyIdToken(token)
} catch (ex: Exception) {
logger.warn("Auth verify failed: {}", ex.message)
throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "Invalid token")
}
val user = appUserRepo.findByFirebaseUid(decoded.uid)
?: throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "User not found")
logger.info("Auth verify resolved uid={}, userId={}", decoded.uid, user.id)
return MyPrincipal(
userId = user.id ?: throw ResponseStatusException(HttpStatus.UNAUTHORIZED, "User id missing"),
firebaseUid = decoded.uid
)
}
}
data class AuthResponse(
val user: UserResponse,
val properties: List<PropertyUserResponse>
)