我正在尝试遵循 Spring Boot OAuth2 示例,遗憾的是它似乎有点过时了。本文介绍了一个简单的 Spring Boot 应用程序,该应用程序将登录外包给 OAuth 2.0 身份验证提供程序,在本例中为 GitHub。现在,一旦 pom.xml 获得新的依赖项
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
以及
github
中相应的
application.yml
设置
spring:
application:
name: MyTestApp
security:
oauth2:
client:
registration:
github:
clientId: 983rkjhsaf809faj3
clientSecret: 0af98s09gdf8sj3l5rjadsf98a7fdvdsaf
行为发生变化,调用
http://localhost:8080
自动重定向到 GitHub OAuth 2.0 登录页面。登录后,重定向会将用户发送回 http://localhost:8080
作为登录用户,显示项目中定义的 index.html
的内容。
到目前为止这还不错,但也许未登录的用户也应该可以查看
http://localhost:8080
的根目录,即"/"
。将它们发送到GitHub登录页面将是错误的。因此,本文提出用类 WebSecurityConfigurerAdapter
来扩展代码,而当前 Spring Security 版本 6.4.1 中已经不存在该类了。我猜显示的示例适用于 Spring Security 5(?)。
因此,我尝试使用SecurityFilterChain
以
新方式添加安全配置。
@Configuration
public class SecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/", "/error", "/webjars/**").permitAll()
.anyRequest().authenticated()
)
.exceptionHandling(e -> e
.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
)
.oauth2Login((oauth2Login) -> oauth2Login
.userInfoEndpoint((userInfo) -> userInfo
.userAuthoritiesMapper(grantedAuthoritiesMapper())
)
);
return http.build();
}
private GrantedAuthoritiesMapper grantedAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach((authority) -> {
GrantedAuthority mappedAuthority;
if (authority instanceof OAuth2UserAuthority) {
OAuth2UserAuthority userAuthority = (OAuth2UserAuthority) authority;
mappedAuthority = new OAuth2UserAuthority("OAUTH2_USER", userAuthority.getAttributes());
} else {
mappedAuthority = authority;
}
mappedAuthorities.add(mappedAuthority);
});
return mappedAuthorities;
};
}
}
这里我明确地用
permitAll()
声明“/”,这应该是“指定任何人都允许的URL。”因此,我不希望Spring将用户重定向到GitHub登录页面。但确实如此!文章还建议添加一个 .exceptionHandling(...)
方法并在调用时发送 UNAUTHORIZED
。但现在我打电话给HTTP ERROR 401
时总是得到http://localhost:8080
。
我想要实现的目标很简单:
http://localhost:8080
(因此,指向“/”),无论是否登录。permitAll()
定义的 URL 之外的任何 URL,我希望他们获得 HTTP ERROR 401
。我怎样才能做到这一点?安全过滤器链的哪一部分扰乱了这个想法?
访问
http://localhost:8080
时,由于我们没有为/
定义映射请求,所以请求匹配到WelcomePageHandlerMapping
,就会转发到/index.html
,而/index.html
无法通过安全过滤器,除非同时添加它允许像这样:
.requestMatchers("/", "/error", "/webjars/**", "/index.html").permitAll()