用途
本技能用于指导智能体在 Vaadin 25 应用中通过 Spring Security 实现安全防护。当用户要求“添加安全”“添加登录”“创建登录页”等任务时使用。技能覆盖 Java/Flow 视图的安全配置,包括登录、访问控制、登出与 OAuth2/OpenID Connect 集成。
主要能力
- Spring Security 配置:使用 VaadinSecurityConfigurer.vaadin() 自动处理 CSRF、登出、请求缓存、异常处理、授权请求与导航访问控制。
- 登录视图:使用内置 LoginForm 组件创建登录页,兼容密码管理器并自动处理 CSRF 令牌。
- 视图访问控制:通过 @AnonymousAllowed、@PermitAll、@RolesAllowed、@DenyAll 注解控制视图访问。
- 程序化访问检查:注入 AuthenticationContext 检查角色或获取用户信息。
- 登出:推荐使用 AuthenticationContext.logout(),也可使用 SecurityContextLogoutHandler。
- OAuth2/OpenID Connect:支持 Google、GitHub、Keycloak、Okta、Azure AD 等身份提供商。
使用方式
设置 Spring Security
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
创建安全配置类:
@EnableWebSecurity
@Configuration
public class SecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
configurer.loginView(LoginView.class);
});
return http.build();
}
@Bean
public UserDetailsManager userDetailsManager() {
// WARNING: In-memory users for development only.
// Use JDBC, LDAP, or OAuth2 in production.
var user = User.withUsername("user")
.password("{noop}user")
.roles("USER")
.build();
var admin = User.withUsername("admin")
.password("{noop}admin")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
登录视图
使用 LoginForm 创建登录页,关键点包括:autoLayout = false、@AnonymousAllowed、login.setAction("login")、BeforeEnterObserver 检查 ?error 参数,并在 SecurityConfig 中注册 loginView(LoginView.class)。
视图访问控制
| 注解 | 访问级别 | 典型用途 |
|---|---|---|
| @AnonymousAllowed | 任何人(无需登录) | 登录视图、公开落地页 |
| @PermitAll | 任何已认证用户 | 仪表盘、用户资料 |
| @RolesAllowed("ADMIN") | 指定角色用户 | 管理面板、用户管理 |
| @DenyAll | 无人 | 无注解时的默认值 |
注意:Vaadin 中 @PermitAll 表示“任何已认证用户”,与标准 Jakarta Security 不同;真正公开视图应使用 @AnonymousAllowed。
注解解析规则:无注解默认 @DenyAll;继承最近的已注解父类;子类注解覆盖父类;接口注解不检查;布局与视图独立检查,两者都必须授权;优先级 @DenyAll > @AnonymousAllowed > @RolesAllowed > @PermitAll。
程序化访问检查
注入 AuthenticationContext 检查角色或获取用户信息:
@Route("settings")
@PermitAll
public class SettingsView extends VerticalLayout {
public SettingsView(AuthenticationContext authContext) {
authContext.getAuthenticatedUser(UserDetails.class)
.ifPresent(user -> add(new H2("Welcome " + user.getUsername())));
if (authContext.hasRole(Roles.ADMIN)) {
add(new Button("Admin Settings", event -> {
// show admin-only settings
}));
}
}
}
登出
推荐使用 AuthenticationContext.logout(),它自动处理会话失效与重定向。AuthenticationContext 字段必须声明为 transient。默认登出后重定向到 /,可通过 configurer.loginView(LoginView.class, "/goodbye") 自定义。
OAuth2 / OpenID Connect
添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
Google 配置示例:
spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID}
spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET}
spring.security.oauth2.client.registration.google.scope=openid,profile,email
Keycloak 配置示例:
spring.security.oauth2.client.registration.keycloak.provider=keycloak
spring.security.oauth2.client.registration.keycloak.client-id=my-client-id
spring.security.oauth2.client.registration.keycloak.client-secret=${KEYCLOAK_CLIENT_SECRET}
spring.security.oauth2.client.registration.keycloak.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.keycloak.scope=openid,profile
spring.security.oauth2.client.provider.keycloak.issuer-uri=http://keycloak.local:8180/realms/my-app
OAuth2 的 SecurityConfig 使用 oauth2LoginPage() 替代 loginView():
http.with(VaadinSecurityConfigurer.vaadin(), configurer -> {
configurer.oauth2LoginPage(
"/oauth2/authorization/google",
"{baseUrl}");
});
使用 OAuth2 时无需 LoginView 类,身份提供商负责登录界面。
适用场景
- 为 Vaadin 25 应用添加登录与访问控制。
- 使用注解保护 Java/Flow 视图。
- 集成外部身份提供商(Google、GitHub、Keycloak、Okta、Azure AD)。
- 实现登出与用户信息展示。
限制与注意事项
- 视图安全应使用注解,而非 URL 模式匹配;Vaadin 所有视图共用一个 servlet 端点,HttpSecurity 的 requestMatchers 无法控制视图访问。URL 模式规则仍适用于 REST API 等非 Vaadin 端点。
- 不要在视图上使用 @Secured 或 @PreAuthorize,这些 Spring Security 注解不受支持。
- 不要硬编码凭据;内存 {noop} 密码仅用于开发。
- 登录视图必须设置 autoLayout = false。
- 布局与视图都必须独立授权。
- 使用 SecurityContextLogoutHandler 时必须先重定向再调用,推荐使用 AuthenticationContext.logout()。
- 使用 Vaadin MCP 工具查询最新文档时,vaadin_version 设为 "25",ui_language 设为 "java"。
详细速查表(安全注解、OAuth2 提供商配置、登录视图清单、SecurityConfig 模板)见 references/security-patterns.md。