【发布时间】:2022-01-10 10:45:45
【问题描述】:
我的所有请求都以 403 Forbidden 响应返回。 我发送的 firebase 令牌已成功验证,所以我不确定我在设置时缺少什么步骤?我只是想获得一个简单的流程,其中我的端点必须在标头中具有有效的 firebase JWT 令牌(在排除的健康端点之外)。
当前步骤:
- 已创建自定义 OncePerRequestFilter 并在相应的端点上命中
- 授权标头令牌已成功验证
- 身份验证对象被创建为 UsernamePasswordAuthenticationToken,在其中跟踪 firebase 令牌和用户 UID。
- SecurityContext 使用新的身份验证对象设置。
- ????
响应:{ "时间戳": "2022-01-09T16:44:08.342+00:00", “状态”:403, “错误”:“禁止”, "message": "拒绝访问", “路径”:“/v1/dev/overweight/service/user/register” }
被排除在身份验证之外的我的健康端点也能够成功拨打电话。
@EnableWebSecurity
@Configuration
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {
@Value("${server.servlet.context-path:''}")
private String contextPath;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and()
.csrf().disable()
.addFilterBefore(new FireBaseFilter(), UsernamePasswordAuthenticationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/health/**").permitAll()
.anyRequest().authenticated();
}
@Override //src: https://www.baeldung.com/spring-cors
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins(
"http://localhost:8080",
"http://localhost:3000"
).allowedMethods("*");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Slf4j
public class FireBaseFilter extends OncePerRequestFilter {
private List<String> skipUrls = Arrays.asList("/health/**");
private static final String AUTH_HEADER = "Authorization";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authToken = request.getHeader(AUTH_HEADER).substring(7);
if (!StringUtils.isEmpty(authToken)) {
Authentication auth = getAuthentication(authToken);
SecurityContextHolder.getContext().setAuthentication(auth);
}
filterChain.doFilter(request, response);
}
private Authentication getAuthentication(String jwtToken) {
FirebaseToken token = verifyFireBaseToken(jwtToken);
return new UsernamePasswordAuthenticationToken(token.getUid(), token);
}
private FirebaseToken verifyFireBaseToken(String jwtToken) {
if (StringUtils.isEmpty(jwtToken)) {
throw new IllegalArgumentException("idToken is blank");
}
try {
return FirebaseAuth.getInstance().verifyIdToken(jwtToken, true);
} catch (FirebaseAuthException e) {
this.logger.error("exception thrown verifying firebase token");
}
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return skipUrls.stream().anyMatch(p -> new AntPathMatcher().match(p, request.getServletPath()));
}
}
【问题讨论】:
-
如果您删除
.addFilterBefore(new FireBaseFilter(), UsernamePasswordAuthenticationFilter.class),您并没有写到您的代码正在运行。那么问题是您的自定义过滤器。您未通过身份验证:return new UsernamePasswordAuthenticationToken(token.getUid(), token);您必须使用其他具有权限的构造器。 -
@dur 嘿,伙计!非常感谢您的帮助,如果我听起来很粗鲁,请道歉。非常感谢您的帮助
-
我仍然建议您改用 spring security 的内置 jwt 功能并对其进行自定义,而不是编写自定义过滤器。
-
@Toerkumlare 你能给出更多的理由吗?我认为这种方式应该让我更好地控制正在发生的事情,并允许我使用 Firebase SDK 来验证一个令牌,这将阻止对授权服务器的往返 API 调用。此外,我还没有看到不遵循这种设计方法的 Firebase Auth 示例。
-
为什么?因为编写自定义安全性是不好的做法。 Spring security 提供了 jwt 功能,让你不用自己写。 Spring security jwt 功能经过实战测试,运行 100000 个应用程序,并经过数百个审查。一段错误的代码、一个糟糕的实现以及您的整个应用程序数据都可能受到损害。自定义安全解决方案是不好的做法,使用安全框架的意义何在,由安全框架专家在您不打算使用时编写。
标签: java spring-boot spring-security firebase-authentication jwt