导航到另一条路线 - 重新路由回 loginView
Navigating to another route - rerouting back to loginView
问题:成功登录后,我想导航到“主页”视图。不幸的是,它只是闪烁并返回到登录视图。
我正在使用 vaadin 会话来存储登录的用户数据:
VaadinSession.getCurrent().setAttribute(UserModel::class.java, result.second!!)
将 HomeView 路由设置为可供当前会话访问:
RouteConfiguration.forSessionScope().setRoute(AdminPanelRoute.HOME, HomeView::class.java)
导航到主页视图:
ui.get().navigate(HomeView::class.java)
LoginView.kt内容:
import com.fd.jvmbackend.data.model.UserModel
import com.fd.jvmbackend.views.AdminPanelRoute
import com.fd.jvmbackend.views.BaseView
import com.fd.jvmbackend.views.home.HomeView
import com.vaadin.flow.component.AttachEvent
import com.vaadin.flow.component.DetachEvent
import com.vaadin.flow.component.Unit
import com.vaadin.flow.component.button.Button
import com.vaadin.flow.component.button.ButtonVariant
import com.vaadin.flow.component.html.Label
import com.vaadin.flow.component.textfield.TextFieldVariant
import com.vaadin.flow.router.PageTitle
import com.vaadin.flow.router.Route
import com.vaadin.flow.router.RouteConfiguration
import com.vaadin.flow.server.VaadinSession
@Route(value = AdminPanelRoute.LOGIN)
@PageTitle("Login | FD CMS")
class LoginView() : BaseView(false) {
private val TAG = "LoginView"
private var viewModel: LoginViewModel? = null
override fun onAttach(attachEvent: AttachEvent?) {
super.onAttach(attachEvent)
viewModel = LoginViewModel()
val label = Label("Welcome.")
val loginField = getLoginTextField("Login", "ex: mike", true, true)
loginField.addThemeVariants(TextFieldVariant.MATERIAL_ALWAYS_FLOAT_LABEL)
loginField.value = "admin"
val passwordField = getPasswordField("Password", "ex. myLongPassword", true, true, true)
passwordField.value = "pass"
passwordField.addThemeVariants(TextFieldVariant.MATERIAL_ALWAYS_FLOAT_LABEL)
val button = Button("Log in with credentials")
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY)
button.setWidth(15F, Unit.PERCENTAGE)
button.addClickListener { event ->
ui.get().access {
VaadinSession.getCurrent().session.invalidate()
VaadinSession.getCurrent().close()
RouteConfiguration.forSessionScope().removeRoute(AdminPanelRoute.HOME)
}
viewModel?.onLoginClicked(loginField.value, passwordField.value) { result ->
println("$TAG -> [onLoginClicked] result -> ${result.first} / ${result.second}")
if (result.first) {
VaadinSession.getCurrent().setAttribute(UserModel::class.java, result.second!!)
println("$TAG -> [onLoginClicked] getAttribute -> ${VaadinSession.getCurrent().getAttribute(UserModel::class.java)} / state -> ${VaadinSession.getCurrent().state.name}")
RouteConfiguration.forSessionScope().setRoute(AdminPanelRoute.HOME, HomeView::class.java)
ui.get().navigate(HomeView::class.java)
}
}
}
add(label)
add(loginField)
add(passwordField)
add(button)
}
override fun onDetach(detachEvent: DetachEvent?) {
viewModel?.onCleared()
viewModel = null
super.onDetach(detachEvent)
}
}
LoginViewModel.kt:
import com.fd.jvmbackend.data.model.UserModel
import com.fd.jvmbackend.extensions.isNotNull
import com.fd.jvmbackend.repository.UserRepository
import com.fd.jvmbackend.service.AdminAuthorizationService
import com.fd.jvmbackend.util.AppInfo
import com.fd.jvmbackend.views.ViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class LoginViewModel() : ViewModel() {
private val TAG = "LoginViewModel"
private val userRepository: UserRepository by lazy {
UserRepository(AppInfo.production)
}
private val adminAuthorizationService: AdminAuthorizationService by lazy {
AdminAuthorizationService(AppInfo.production)
}
init {
viewModelScope.launch {
setPageTitle("Login")
}
}
fun onLoginClicked(login: String?, password: String?, result: (Pair<Boolean, UserModel?>) -> Unit) {
println("$TAG -> onLoginClicked / login _> ${login} / password _> ${password}")
setIsLoading(true)
setErrorText(null)
val inputValuesErrorText = inputValuesErrorText(login, password)
println("$TAG -> onLoginClicked / inputValuesErrorText _> ${inputValuesErrorText} / isEmpty _> ${inputValuesErrorText.isEmpty()}")
val authorized = adminAuthorizationService.isAuthorized(login!!, password!!)
val resultError = if (inputValuesErrorText.isNotNull()) {
inputValuesErrorText
} else {
if (authorized) null else "Wrong credentials!"
}
setErrorText(resultError)
setIsLoading(false)
result.invoke(Pair(authorized, if (authorized) userRepository.getUserByUsername(login) else null))
}
private fun inputValuesErrorText(login: String?, password: String?): String {
val stringBuilder = StringBuilder()
if (login?.length == 0) {
stringBuilder.appendLine("Login is empty.")
}
if (password?.length == 0) {
stringBuilder.appendLine("Password is empty.")
}
return stringBuilder.toString()
}
}
HomeView.kt:
import com.fd.jvmbackend.data.model.UserModel
import com.fd.jvmbackend.views.BaseView
import com.fd.jvmbackend.views.login.LoginView
import com.vaadin.flow.component.AttachEvent
import com.vaadin.flow.component.DetachEvent
import com.vaadin.flow.component.html.Label
import com.vaadin.flow.router.PageTitle
import com.vaadin.flow.server.VaadinSession
//@Route(value = AdminPanelRoute.HOME)
@PageTitle("Home | FD CMS")
class HomeView() : BaseView(true) {
private val TAG = "HomeView"
private val loggedInUser:UserModel? by lazy {
VaadinSession.getCurrent().getAttribute(UserModel::class.java) as? UserModel
}
override fun onAttach(attachEvent: AttachEvent?) {
super.onAttach(attachEvent)
// setId("login-view")
// if(loggedInUser == null){
// clearSession()
// }
val label = Label("HOME.")
add(label)
}
override fun onDetach(detachEvent: DetachEvent?) {
super.onDetach(detachEvent)
}
private fun clearSession(){
VaadinSession.getCurrent().session.invalidate()
VaadinSession.getCurrent().close()
ui.get().navigate(LoginView::class.java)
}
}
Spring安全配置:
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
@EnableWebSecurity
open class SecurityConfiguration : WebSecurityConfigurerAdapter() {
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.csrf().disable().authorizeRequests().antMatchers("/**").permitAll()
// Allow all Vaadin internal requests.
.requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
}
override fun configure(web: WebSecurity?) {
super.configure(web)
web?.ignoring()?.antMatchers(
// Client-side JS
"/VAADIN/**",
// the standard favicon URI
"/favicon.ico",
// the robots exclusion standard
"/robots.txt",
// web application manifest
"/manifest.webmanifest",
"/sw.js",
"/offline.html",
// icons and images
"/icons/**",
"/images/**",
"/styles/**",
// (development mode) H2 debugging console
"/h2-console/**");
}
}
App.kt:
import com.rfksystems.blake2b.security.Blake2bProvider
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
import java.security.Security
@SpringBootApplication(exclude = [SecurityAutoConfiguration::class, JacksonAutoConfiguration::class, ErrorMvcAutoConfiguration::class])
open class App {
companion object {
@JvmStatic
fun main(args: Array<String>) {
Security.addProvider(Blake2bProvider())
SpringApplication.run(App::class.java, *args)
}
}
}
AppShellConfigurator:
import com.vaadin.flow.component.page.AppShellConfigurator
import com.vaadin.flow.component.page.Push
import com.vaadin.flow.shared.communication.PushMode
import com.vaadin.flow.theme.Theme
import com.vaadin.flow.theme.lumo.Lumo
@Theme(themeClass = Lumo::class, variant = Lumo.DARK)
@Push(PushMode.AUTOMATIC)
class AppShell : AppShellConfigurator
AdminAuthorizationService.kt:
import com.fd.jvmbackend.data.constants.UserRole
import com.fd.jvmbackend.data.constants.UserState
import com.fd.jvmbackend.service.exception.UserNotFoundException
import com.fd.jvmbackend.util.base.validation.Argon2PasswordHash
import com.fd.jvmbackend.util.generator.HashTextGenerator
import com.vaadin.flow.server.VaadinSession
class AdminAuthorizationService(private val productionMode: Boolean) : BaseService(productionMode) {
private val TAG = "AdminAuthorizationService"
private val emailService: EmailService by lazy {
EmailService(productionMode)
}
fun isAuthorized(username: String, password: String): Boolean {
createDefaultAdminUserIfNotExists()
println("$TAG -> [validateCredentials] !!!!!!!!")
val valid = validateCredentials(username, password)
if (valid) {
}
if (!productionMode) {
println("$TAG -> [isAuthorized] / valid -> $valid")
}
return valid
}
fun logout() {
VaadinSession.getCurrent().session.invalidate()
VaadinSession.getCurrent().close()
}
private fun createDefaultAdminUserIfNotExists() {
val defaultDevUsername = "admin"
val defaultDevPass =
if (productionMode) HashTextGenerator.get(defaultDevUsername, 30, 100, true, true) else "pass"
if (!userRepository.userWithUsernameExists(defaultDevUsername)) {
val passwordHashArgon2 = Argon2PasswordHash.get(defaultDevPass!!)
val userEmail = "admin@flyingdynamite.com"
val created = userRepository.createUser(
defaultDevUsername,
passwordHashArgon2,
userEmail,
"Admin",
"Admin",
UserRole.ADMIN,
UserState.ENABLED
)
if (!productionMode) {
println("$TAG -> [createDefaultAdminUserIfNotExists] / defaultDevUsername -> $defaultDevUsername")
println("$TAG -> [createDefaultAdminUserIfNotExists] / defaultDevPass -> $defaultDevPass")
println("$TAG -> [createDefaultAdminUserIfNotExists] / created -> $created")
}
if (created && productionMode) {
val sent = emailService.send("Developer admin user created", defaultDevPass, userEmail)
println("$TAG -> [createDefaultAdminUserIfNotExists] / email sent -> $sent")
}
}
}
private fun validateCredentials(username: String, password: String): Boolean {
return try {
val userProfile = userRepository.getUserProfileByUsername(username)
val user = userRepository.getUserByTokenId(userProfile.tokenId)
val state = user.state == UserState.ENABLED.state
val role = user.role.equals(UserRole.ADMIN.type, false)
val passwordVerify = Argon2PasswordHash.verify(password!!, user.passwordHash)
if (!productionMode) {
println("$TAG -> [validateCredentials] / userProfile -> $userProfile")
println("$TAG -> [validateCredentials] / user -> $user")
println("$TAG -> [validateCredentials] / state -> $state / role -> $role / passwordVerify -> $passwordVerify")
}
val valid = state && role && passwordVerify
valid
} catch (e: UserNotFoundException) {
println("$TAG -> [validateCredentials.UserNotFoundException] -> ${e.message}")
if (!productionMode) {
e.printStackTrace()
}
false
}
}
}
我试过像这里一样做这种类似的方式 - https://github.com/alejandro-du/vaadin-auth-example
不幸的是,这也行不通。
这就是发生的事情 -> https://wetransfer.com/downloads/43855a41690ff01f3d42114ff337a9e620220406163956/90bbbc
如何解决这个问题?
在 LoginView.kt
中的 ButtonClickListener
中,您正在 使 ui.get().access
表达式中的会话 无效。失效需要一些时间,这就是为什么到主页视图的路由会显示很短的时间,直到失效完成并且框架正在路由回登录视图。
(此外,我建议使用 BeforeEnter
- 和 BeforeLeaveObserver
接口,而不是 onAttach
和 onDetach
方法。)
问题:成功登录后,我想导航到“主页”视图。不幸的是,它只是闪烁并返回到登录视图。
我正在使用 vaadin 会话来存储登录的用户数据:
VaadinSession.getCurrent().setAttribute(UserModel::class.java, result.second!!)
将 HomeView 路由设置为可供当前会话访问:
RouteConfiguration.forSessionScope().setRoute(AdminPanelRoute.HOME, HomeView::class.java)
导航到主页视图:
ui.get().navigate(HomeView::class.java)
LoginView.kt内容:
import com.fd.jvmbackend.data.model.UserModel
import com.fd.jvmbackend.views.AdminPanelRoute
import com.fd.jvmbackend.views.BaseView
import com.fd.jvmbackend.views.home.HomeView
import com.vaadin.flow.component.AttachEvent
import com.vaadin.flow.component.DetachEvent
import com.vaadin.flow.component.Unit
import com.vaadin.flow.component.button.Button
import com.vaadin.flow.component.button.ButtonVariant
import com.vaadin.flow.component.html.Label
import com.vaadin.flow.component.textfield.TextFieldVariant
import com.vaadin.flow.router.PageTitle
import com.vaadin.flow.router.Route
import com.vaadin.flow.router.RouteConfiguration
import com.vaadin.flow.server.VaadinSession
@Route(value = AdminPanelRoute.LOGIN)
@PageTitle("Login | FD CMS")
class LoginView() : BaseView(false) {
private val TAG = "LoginView"
private var viewModel: LoginViewModel? = null
override fun onAttach(attachEvent: AttachEvent?) {
super.onAttach(attachEvent)
viewModel = LoginViewModel()
val label = Label("Welcome.")
val loginField = getLoginTextField("Login", "ex: mike", true, true)
loginField.addThemeVariants(TextFieldVariant.MATERIAL_ALWAYS_FLOAT_LABEL)
loginField.value = "admin"
val passwordField = getPasswordField("Password", "ex. myLongPassword", true, true, true)
passwordField.value = "pass"
passwordField.addThemeVariants(TextFieldVariant.MATERIAL_ALWAYS_FLOAT_LABEL)
val button = Button("Log in with credentials")
button.addThemeVariants(ButtonVariant.LUMO_PRIMARY)
button.setWidth(15F, Unit.PERCENTAGE)
button.addClickListener { event ->
ui.get().access {
VaadinSession.getCurrent().session.invalidate()
VaadinSession.getCurrent().close()
RouteConfiguration.forSessionScope().removeRoute(AdminPanelRoute.HOME)
}
viewModel?.onLoginClicked(loginField.value, passwordField.value) { result ->
println("$TAG -> [onLoginClicked] result -> ${result.first} / ${result.second}")
if (result.first) {
VaadinSession.getCurrent().setAttribute(UserModel::class.java, result.second!!)
println("$TAG -> [onLoginClicked] getAttribute -> ${VaadinSession.getCurrent().getAttribute(UserModel::class.java)} / state -> ${VaadinSession.getCurrent().state.name}")
RouteConfiguration.forSessionScope().setRoute(AdminPanelRoute.HOME, HomeView::class.java)
ui.get().navigate(HomeView::class.java)
}
}
}
add(label)
add(loginField)
add(passwordField)
add(button)
}
override fun onDetach(detachEvent: DetachEvent?) {
viewModel?.onCleared()
viewModel = null
super.onDetach(detachEvent)
}
}
LoginViewModel.kt:
import com.fd.jvmbackend.data.model.UserModel
import com.fd.jvmbackend.extensions.isNotNull
import com.fd.jvmbackend.repository.UserRepository
import com.fd.jvmbackend.service.AdminAuthorizationService
import com.fd.jvmbackend.util.AppInfo
import com.fd.jvmbackend.views.ViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class LoginViewModel() : ViewModel() {
private val TAG = "LoginViewModel"
private val userRepository: UserRepository by lazy {
UserRepository(AppInfo.production)
}
private val adminAuthorizationService: AdminAuthorizationService by lazy {
AdminAuthorizationService(AppInfo.production)
}
init {
viewModelScope.launch {
setPageTitle("Login")
}
}
fun onLoginClicked(login: String?, password: String?, result: (Pair<Boolean, UserModel?>) -> Unit) {
println("$TAG -> onLoginClicked / login _> ${login} / password _> ${password}")
setIsLoading(true)
setErrorText(null)
val inputValuesErrorText = inputValuesErrorText(login, password)
println("$TAG -> onLoginClicked / inputValuesErrorText _> ${inputValuesErrorText} / isEmpty _> ${inputValuesErrorText.isEmpty()}")
val authorized = adminAuthorizationService.isAuthorized(login!!, password!!)
val resultError = if (inputValuesErrorText.isNotNull()) {
inputValuesErrorText
} else {
if (authorized) null else "Wrong credentials!"
}
setErrorText(resultError)
setIsLoading(false)
result.invoke(Pair(authorized, if (authorized) userRepository.getUserByUsername(login) else null))
}
private fun inputValuesErrorText(login: String?, password: String?): String {
val stringBuilder = StringBuilder()
if (login?.length == 0) {
stringBuilder.appendLine("Login is empty.")
}
if (password?.length == 0) {
stringBuilder.appendLine("Password is empty.")
}
return stringBuilder.toString()
}
}
HomeView.kt:
import com.fd.jvmbackend.data.model.UserModel
import com.fd.jvmbackend.views.BaseView
import com.fd.jvmbackend.views.login.LoginView
import com.vaadin.flow.component.AttachEvent
import com.vaadin.flow.component.DetachEvent
import com.vaadin.flow.component.html.Label
import com.vaadin.flow.router.PageTitle
import com.vaadin.flow.server.VaadinSession
//@Route(value = AdminPanelRoute.HOME)
@PageTitle("Home | FD CMS")
class HomeView() : BaseView(true) {
private val TAG = "HomeView"
private val loggedInUser:UserModel? by lazy {
VaadinSession.getCurrent().getAttribute(UserModel::class.java) as? UserModel
}
override fun onAttach(attachEvent: AttachEvent?) {
super.onAttach(attachEvent)
// setId("login-view")
// if(loggedInUser == null){
// clearSession()
// }
val label = Label("HOME.")
add(label)
}
override fun onDetach(detachEvent: DetachEvent?) {
super.onDetach(detachEvent)
}
private fun clearSession(){
VaadinSession.getCurrent().session.invalidate()
VaadinSession.getCurrent().close()
ui.get().navigate(LoginView::class.java)
}
}
Spring安全配置:
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.builders.WebSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
@EnableWebSecurity
open class SecurityConfiguration : WebSecurityConfigurerAdapter() {
@Throws(Exception::class)
override fun configure(http: HttpSecurity) {
http.csrf().disable().authorizeRequests().antMatchers("/**").permitAll()
// Allow all Vaadin internal requests.
.requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
}
override fun configure(web: WebSecurity?) {
super.configure(web)
web?.ignoring()?.antMatchers(
// Client-side JS
"/VAADIN/**",
// the standard favicon URI
"/favicon.ico",
// the robots exclusion standard
"/robots.txt",
// web application manifest
"/manifest.webmanifest",
"/sw.js",
"/offline.html",
// icons and images
"/icons/**",
"/images/**",
"/styles/**",
// (development mode) H2 debugging console
"/h2-console/**");
}
}
App.kt:
import com.rfksystems.blake2b.security.Blake2bProvider
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
import java.security.Security
@SpringBootApplication(exclude = [SecurityAutoConfiguration::class, JacksonAutoConfiguration::class, ErrorMvcAutoConfiguration::class])
open class App {
companion object {
@JvmStatic
fun main(args: Array<String>) {
Security.addProvider(Blake2bProvider())
SpringApplication.run(App::class.java, *args)
}
}
}
AppShellConfigurator:
import com.vaadin.flow.component.page.AppShellConfigurator
import com.vaadin.flow.component.page.Push
import com.vaadin.flow.shared.communication.PushMode
import com.vaadin.flow.theme.Theme
import com.vaadin.flow.theme.lumo.Lumo
@Theme(themeClass = Lumo::class, variant = Lumo.DARK)
@Push(PushMode.AUTOMATIC)
class AppShell : AppShellConfigurator
AdminAuthorizationService.kt:
import com.fd.jvmbackend.data.constants.UserRole
import com.fd.jvmbackend.data.constants.UserState
import com.fd.jvmbackend.service.exception.UserNotFoundException
import com.fd.jvmbackend.util.base.validation.Argon2PasswordHash
import com.fd.jvmbackend.util.generator.HashTextGenerator
import com.vaadin.flow.server.VaadinSession
class AdminAuthorizationService(private val productionMode: Boolean) : BaseService(productionMode) {
private val TAG = "AdminAuthorizationService"
private val emailService: EmailService by lazy {
EmailService(productionMode)
}
fun isAuthorized(username: String, password: String): Boolean {
createDefaultAdminUserIfNotExists()
println("$TAG -> [validateCredentials] !!!!!!!!")
val valid = validateCredentials(username, password)
if (valid) {
}
if (!productionMode) {
println("$TAG -> [isAuthorized] / valid -> $valid")
}
return valid
}
fun logout() {
VaadinSession.getCurrent().session.invalidate()
VaadinSession.getCurrent().close()
}
private fun createDefaultAdminUserIfNotExists() {
val defaultDevUsername = "admin"
val defaultDevPass =
if (productionMode) HashTextGenerator.get(defaultDevUsername, 30, 100, true, true) else "pass"
if (!userRepository.userWithUsernameExists(defaultDevUsername)) {
val passwordHashArgon2 = Argon2PasswordHash.get(defaultDevPass!!)
val userEmail = "admin@flyingdynamite.com"
val created = userRepository.createUser(
defaultDevUsername,
passwordHashArgon2,
userEmail,
"Admin",
"Admin",
UserRole.ADMIN,
UserState.ENABLED
)
if (!productionMode) {
println("$TAG -> [createDefaultAdminUserIfNotExists] / defaultDevUsername -> $defaultDevUsername")
println("$TAG -> [createDefaultAdminUserIfNotExists] / defaultDevPass -> $defaultDevPass")
println("$TAG -> [createDefaultAdminUserIfNotExists] / created -> $created")
}
if (created && productionMode) {
val sent = emailService.send("Developer admin user created", defaultDevPass, userEmail)
println("$TAG -> [createDefaultAdminUserIfNotExists] / email sent -> $sent")
}
}
}
private fun validateCredentials(username: String, password: String): Boolean {
return try {
val userProfile = userRepository.getUserProfileByUsername(username)
val user = userRepository.getUserByTokenId(userProfile.tokenId)
val state = user.state == UserState.ENABLED.state
val role = user.role.equals(UserRole.ADMIN.type, false)
val passwordVerify = Argon2PasswordHash.verify(password!!, user.passwordHash)
if (!productionMode) {
println("$TAG -> [validateCredentials] / userProfile -> $userProfile")
println("$TAG -> [validateCredentials] / user -> $user")
println("$TAG -> [validateCredentials] / state -> $state / role -> $role / passwordVerify -> $passwordVerify")
}
val valid = state && role && passwordVerify
valid
} catch (e: UserNotFoundException) {
println("$TAG -> [validateCredentials.UserNotFoundException] -> ${e.message}")
if (!productionMode) {
e.printStackTrace()
}
false
}
}
}
我试过像这里一样做这种类似的方式 - https://github.com/alejandro-du/vaadin-auth-example
不幸的是,这也行不通。 这就是发生的事情 -> https://wetransfer.com/downloads/43855a41690ff01f3d42114ff337a9e620220406163956/90bbbc
如何解决这个问题?
在 LoginView.kt
中的 ButtonClickListener
中,您正在 使 ui.get().access
表达式中的会话 无效。失效需要一些时间,这就是为什么到主页视图的路由会显示很短的时间,直到失效完成并且框架正在路由回登录视图。
(此外,我建议使用 BeforeEnter
- 和 BeforeLeaveObserver
接口,而不是 onAttach
和 onDetach
方法。)