我定义了以下路线和视图:
private void createDrawer() {
Tabs tabs = new Tabs();
tabs.add(
createTab(VaadinIcon.HOME, "Home", HomeView.class),
createTab(VaadinIcon.DASHBOARD, "Dashboard", DashboardView.class),
createTab(VaadinIcon.INBOX, "Inbox", InboxView.class),
createTab(VaadinIcon.WORKPLACE, "Jobs", JobsView.class),
createTab(VaadinIcon.USER, "Candidates", CandidatesView.class),
createTab(VaadinIcon.GAVEL, "Administration", AdministrationView.class)
);
tabs.setOrientation(Tabs.Orientation.VERTICAL);
addToDrawer(tabs);
}
private Tab createTab(VaadinIcon viewIcon, String viewName, Class<? extends Component> navigationTarget) {
Icon icon = viewIcon.create();
icon.getStyle()
.set("box-sizing", "border-box")
.set("margin-inline-end", "var(--lumo-space-m)")
.set("margin-inline-start", "var(--lumo-space-xs)")
.set("padding", "var(--lumo-space-xs)");
RouterLink link = new RouterLink();
link.add(icon, new Span(viewName));
link.setRoute(navigationTarget);
link.setTabIndex(-1);
return new Tab(link);
}
每个视图都定义了以下注解,例如
@Scope("prototype")
@Component
@Route(value = "", layout = MainLayout.class)
@PageTitle("Home")
@PermitAll
public class HomeView extends VerticalLayout {
由于@PermitAll
的原因,它需要来自用户的身份验证。我用Keycloak 18配置了Spring Security,一切都工作正常。当我尝试访问一个安全页面时,例如http://localhost:8080/-系统会自动将我重定向到Keycloak登录页面。
现在,我想允许匿名访问我的应用程序的主页(HomeView)。为此,我将@PermitAll
更改为@AnonymousAllowed
:
@Scope("prototype")
@Component
@Route(value = "", layout = MainLayout.class)
@PageTitle("Home")
@AnonymousAllowed
public class HomeView extends VerticalLayout {
现在,我可以使用匿名用户访问http://localhost:8080/(HomeView)。这很好。但是,当我单击另一个选项卡链接(例如DashboardView
)时,它会显示以下消息:
Could not navigate to 'dashboard'
Available routes:
<root>
administration
candidates
dashboard
inbox
jobs
list
login
This detailed message is only shown when running in development mode. Instead of that I expect that the system will automaticall redirect me to Keycloak login page.
Jmeter 板视图定义:
@Scope("prototype")
@Route(value = "dashboard", layout = MainLayout.class)
@PageTitle("Dashboard")
@PermitAll
public class DashboardView extends VerticalLayout {
我做错了什么,该如何改正?
已更新
我在com.vaadin
上启用了DEBUG
,现在可能会看到以下消息:
2022-07-25 18:35:25.564 DEBUG 18984 --- [nio-8080-exec-8] c.v.flow.spring.SpringViewAccessChecker : Checking access for view com.decisionwanted.ui.views.dashboard.DashboardView
2022-07-25 18:35:25.564 DEBUG 18984 --- [nio-8080-exec-8] c.v.flow.spring.SpringViewAccessChecker : Denied access to view com.decisionwanted.ui.views.dashboard.DashboardView
2022-07-25 18:35:25.567 DEBUG 18984 --- [nio-8080-exec-8] c.v.flow.spring.SpringViewAccessChecker : Checking access for view com.vaadin.flow.router.RouteNotFoundError
2022-07-25 18:35:25.568 DEBUG 18984 --- [nio-8080-exec-8] c.v.flow.spring.SpringViewAccessChecker : Allowed access to view com.vaadin.flow.router.RouteNotFoundError
2022-07-25 18:35:25.580 DEBUG 18984 --- [nio-8080-exec-8] c.vaadin.flow.router.RouteNotFoundError : Route is not found
com.vaadin.flow.router.NotFoundException: null
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:na]
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) ~[na:na]
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) ~[na:na]
at com.vaadin.flow.internal.ReflectTools.createProxyInstance(ReflectTools.java:484) ~[flow-server-23.1.3.jar:23.1.3]
at com.vaadin.flow.internal.ReflectTools.createInstance(ReflectTools.java:452) ~[flow-server-23.1.3.jar:23.1.3]
at com.vaadin.flow.router.BeforeEvent.rerouteToError(BeforeEvent.java:766) ~[flow-server-23.1.3.jar:23.1.3]
at com.vaadin.flow.router.BeforeEvent.rerouteToError(BeforeEvent.java:750) ~[flow-server-23.1.3.jar:23.1.3]
at com.vaadin.flow.server.auth.ViewAccessChecker.beforeEnter(ViewAccessChecker.java:192) ~[flow-server-23.1.3.jar:23.1.3]
这是我的SecurityConfig:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends VaadinWebSecurityConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
final ClientRegistrationRepository clientRegistrationRepository;
final GrantedAuthoritiesMapper authoritiesMapper;
SecurityConfiguration(ClientRegistrationRepository clientRegistrationRepository,
GrantedAuthoritiesMapper authoritiesMapper) {
this.clientRegistrationRepository = clientRegistrationRepository;
this.authoritiesMapper = authoritiesMapper;
SecurityContextHolder.setStrategyName(VaadinAwareSecurityContextHolderStrategy.class.getName());
}
@Bean
public SessionRepository sessionRepository() {
return new SessionRepository();
}
@Bean
public ServletListenerRegistrationBean<SessionRepositoryListener> sessionRepositoryListener() {
var bean = new ServletListenerRegistrationBean<SessionRepositoryListener>();
bean.setListener(new SessionRepositoryListener(sessionRepository()));
return bean;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
// Enable OAuth2 login
.oauth2Login(oauth2Login ->
oauth2Login
.clientRegistrationRepository(clientRegistrationRepository)
.userInfoEndpoint(userInfoEndpoint ->
userInfoEndpoint
// Use a custom authorities mapper to get the roles from the identity provider into the Authentication token
.userAuthoritiesMapper(authoritiesMapper)
)
// Use a Vaadin aware authentication success handler
.successHandler(new VaadinSavedRequestAwareAuthenticationSuccessHandler())
)
// Configure logout
.logout(logout ->
logout
// Enable OIDC logout (requires that we use the 'openid' scope when authenticating)
.logoutSuccessHandler(logoutSuccessHandler())
// When CSRF is enabled, the logout URL normally requires a POST request with the CSRF
// token attached. This makes it difficult to perform a logout from within a Vaadin
// application (since Vaadin uses its own CSRF tokens). By changing the logout endpoint
// to accept GET requests, we can redirect to the logout URL from within Vaadin.
.logoutRequestMatcher(new AntPathRequestMatcher("/logout", "GET"))
);
}
private OidcClientInitiatedLogoutSuccessHandler logoutSuccessHandler() {
var logoutSuccessHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository);
logoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");
return logoutSuccessHandler;
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
// Don't apply security rules on our static pages
web.ignoring().antMatchers("/session-expired");
}
@Bean
public PolicyFactory htmlSanitizer() {
// This is the policy we will be using to sanitize HTML input
return Sanitizers.FORMATTING.and(Sanitizers.BLOCKS).and(Sanitizers.STYLES).and(Sanitizers.LINKS);
}
}
为什么Vaadin不把我重定向到Keycloak登录页面,而是失败了?在这种情况下,如何配置重定向到Keycloak登录页面以验证用户?
1条答案
按热度按时间puruo6ea1#
经过几个小时的调试,我似乎找到了解决此问题的方法:
我创建了自己的类(扩展的
SpringViewAccessChecker
):用我的实现覆盖了Bean:
看起来它现在可以按预期使用Keycloak了