目前我正在尝试在我的 Vaadin 应用程序中添加 OAuth 2.0,该应用程序也适用于我的登录表单。我阅读了有关为 Google 添加 OAuth 的文档。
首先,我添加了所需的依赖项
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
然后我在 application.properties 文件中为 GitHub 和 Google 添加了
client-id
和 client-secret
# Github
spring.security.oauth2.client.registration.github.client-id={id}
spring.security.oauth2.client.registration.github.client-secret={secret}
# Google
spring.security.oauth2.client.registration.google.client-id={id}
spring.security.oauth2.client.registration.google.client-secret={secret}
此后,我设置了我的 Web 配置文件
@Configuration
@EnableWebSecurity
public class VaadinSecurityConfiguration extends VaadinWebSecurity {
private static final String LOGIN_URL = "/login";
private static final String LOGIN_PROCESSING_URL = "/login";
private static final String LOGIN_FAILURE_URL = "/login?error";
private static final String LOGOUT_SUCCESS_URL = "/";
private static final String DENIED_PAGE_URL = "/404";
@Autowired
private UserService userService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests(auth -> {
auth.requestMatchers("/").permitAll();
auth.requestMatchers("/login").permitAll();
auth.requestMatchers("/register").permitAll();
auth.requestMatchers("/icons/**").permitAll();
auth.requestMatchers("/images/**").permitAll();
auth.requestMatchers("/oauth2/**").permitAll();
})
.oauth2Login(oauth -> oauth.loginPage(LOGIN_URL).permitAll())
.formLogin(loginForm -> {
loginForm.loginPage(LOGIN_URL);
loginForm.loginProcessingUrl(LOGIN_PROCESSING_URL);
loginForm.failureUrl(LOGIN_FAILURE_URL);
})
.logout(logout -> logout.logoutSuccessUrl(LOGOUT_SUCCESS_URL))
.exceptionHandling(e -> {
e.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
e.accessDeniedPage(DENIED_PAGE_URL);
});
super.configure(http);
setLoginView(http, LoginView.class);
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authConfiguration) throws Exception {
return authConfiguration.getAuthenticationManager();
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
daoAuthenticationProvider.setUserDetailsService(userService);
return daoAuthenticationProvider;
}
}
然后登录表单
@AnonymousAllowed
@PageTitle("Login")
@Route(value = "login", layout = MainLayout.class)
public class LoginView extends VerticalLayout implements BeforeEnterObserver {
private static final String GITHUB_OAUTH_URL = "/oauth2/code/github";
private static final String GOOGLE_OAUTH_URL = "/oauth2/code/google";
private final LoginForm loginForm = new LoginForm();
public LoginView() {
Anchor githubLoginLink = new Anchor(GITHUB_OAUTH_URL, "Login with Github");
Anchor googleLoginLink = new Anchor(GOOGLE_OAUTH_URL, "Login with Google");
githubLoginLink.getElement().setAttribute("router-ignore", true);
googleLoginLink.getElement().setAttribute("router-ignore", true);
loginForm.setAction("login");
add(
new H1("Welcome to Login Form"),
loginForm,
githubLoginLink,
googleLoginLink
);
}
@Override
public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
if (beforeEnterEvent.getLocation()
.getQueryParameters()
.getParameters()
.containsKey("error")) {
loginForm.setError(true);
}
}
}
这就是当我单击任何锚点时发生的情况。它会将我重定向到锚链接。
示例:
按下 GitHub 锚点后,它会转到
http://localhost:8080/oauth2/code/github
,我认为这不是正确的行为,因为这个
// Set router-ignore attribute so that Vaadin router doesn't handle the login request
githubLoginLink.getElement().setAttribute("router-ignore", true);
googleLoginLink.getElement().setAttribute("router-ignore", true);
取自 Vaadin 官方文档。在此重定向页面上,如果不发生 OAuth,则不会发生任何事情。希望有人能帮忙解决这个问题,干杯!
您定义了两种不同的
SecurityFilterChain
beans:一种带有 Basic
auth,另一种带有 oauth2client()
和 oauth2Login()
。
这两个安全过滤器链必须用
@Order
修饰以确定首先尝试哪个。
第一个尝试的必须有一个
securityMatcher
来定义它适用于哪些请求。在您的情况下,以 Authorization
开头的 Basic
标题上的匹配器似乎是一个不错的候选者。
@Bean
@Order(Ordered.LOWEST_PRECEDENCE - 1)
SecurityFilterChain basicAuthFilterChain(HttpSecurity http) throws Exception {
// process only requests with HTTP Basic Authorization
http.securityMatcher((HttpServletRequest request) -> {
return Optional.ofNullable(request.getHeader(HttpHeaders.AUTHORIZATION)).map(h -> {
return h.toLowerCase().startsWith("basic ");
}).orElse(false);
});
http.httpBasic(withDefaults());
...
return http.build();
}
@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
SecurityFilterChain oauth2ClientFilterChain(HttpSecurity http) throws Exception {
http.oauth2Client(withDefaults());
http.oauth2Login(withDefaults());
...
return http.build();
}