Spring Boot 2 和 Security With JWT 无法提供 Angular 构建的静态内容

Posted

技术标签:

【中文标题】Spring Boot 2 和 Security With JWT 无法提供 Angular 构建的静态内容【英文标题】:Spring Boot 2 and Security With JWT is unable to serve static content of angular build 【发布时间】:2020-10-24 12:17:55 【问题描述】:

我正在使用 Spring Security 和 JWT 身份验证令牌构建 Spring Boot 应用程序,它仅在我提供 Rest api 时运行良好,但现在我也想托管 Angular 文件,所以我在 Spring Boot 的可执行战争中添加了 Angular 构建/WEB-INF/classes/static/,现在我想托管静态目录中的所有文件应该可以从/访问 我尝试了很多东西,下面是我的代码

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
    securedEnabled = true,
    jsr250Enabled = true,
    prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter 

@Autowired
CustomUserDetailsService customUserDetailsService;

@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;

@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() 
    return new JwtAuthenticationFilter();


@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception 
    authenticationManagerBuilder
            .userDetailsService(customUserDetailsService)
            .passwordEncoder(passwordEncoder());


@Bean(BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception 
    return super.authenticationManagerBean();


@Bean
public PasswordEncoder passwordEncoder() 
    return new BCryptPasswordEncoder();


//    @Override
//    public void configure(WebSecurity web) throws Exception 
//                web.ignoring().requestMatchers().antMatchers("/static/**").antMatchers("/api/auth/**");
//    

@Override
protected void configure(HttpSecurity http) throws Exception 
    http
//                .cors()
//                    .and()
//                .csrf()
//                    .disable()
//                .exceptionHandling()
//                    .authenticationEntryPoint(unauthorizedHandler)
//                    .and()
//                .sessionManagement()
//                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//                    .and()
//                .requestMatchers().antMatchers("/static/**").and()
            .authorizeRequests()
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                .antMatchers("/api/auth/**")
                    .permitAll()
                .antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
                    .permitAll()
                .antMatchers("/api/test/**")
                    .permitAll()
                .antMatchers("/", "/static/**")
                    .permitAll()
                .anyRequest()
                    .authenticated();

    // Add our custom JWT security filter
    http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);


WebMvcConfig 是

@Configuration
public class WebMvcConfig implements WebMvcConfigurer 

private final long MAX_AGE_SECS = 3600;

@Override
public void addCorsMappings(CorsRegistry registry) 
    registry.addMapping("/**")
            .allowedOrigins("*")
            .allowedMethods("HEAD", "OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE")
            .maxAge(MAX_AGE_SECS);


@Override
public void configurePathMatch(PathMatchConfigurer configurer) 
    // TODO Auto-generated method stub
    


@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) 
    // TODO Auto-generated method stub
    


@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) 
    // TODO Auto-generated method stub
    


@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) 
    // TODO Auto-generated method stub
    


@Override
public void addFormatters(FormatterRegistry registry) 
    // TODO Auto-generated method stub
    


@Override
public void addInterceptors(InterceptorRegistry registry) 
    // TODO Auto-generated method stub
    


@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) 
//      registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static");


@Override
public void addViewControllers(ViewControllerRegistry registry) 
    // TODO Auto-generated method stub
    


@Override
public void configureViewResolvers(ViewResolverRegistry registry) 
    // TODO Auto-generated method stub
    


@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) 
    // TODO Auto-generated method stub
    


@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) 
    // TODO Auto-generated method stub
    


@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) 
    // TODO Auto-generated method stub
    


@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) 
    // TODO Auto-generated method stub
    


@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) 
    // TODO Auto-generated method stub
    


@Override
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) 
    // TODO Auto-generated method stub
    


@Override
public Validator getValidator() 
    // TODO Auto-generated method stub
    return null;


@Override
public MessageCodesResolver getMessageCodesResolver() 
    // TODO Auto-generated method stub
    return null;




JwtAuthenticationFilter

public class JwtAuthenticationFilter extends OncePerRequestFilter 

@Autowired
private JwtTokenProvider tokenProvider;

@Autowired
private CustomUserDetailsService customUserDetailsService;

private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException 
    try 
        String jwt = getJwtFromRequest(request);

        if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) 
            String userId = tokenProvider.getUserIdFromJWT(jwt);

            /*
                Note that you could also encode the user's username and roles inside JWT claims
                and create the UserDetails object by parsing those claims from the JWT.
                That would avoid the following database hit. It's completely up to you.
             */
            UserDetails userDetails = customUserDetailsService.loadUserById(userId);
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                    userDetails, null, userDetails.getAuthorities());
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

            SecurityContextHolder.getContext().setAuthentication(authentication);
        
     catch (Exception ex) 
        logger.error("Could not set user authentication in security context", ex);
    

    filterChain.doFilter(request, response);


private String getJwtFromRequest(HttpServletRequest request) 
    String bearerToken = request.getHeader("Authorization");
    if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) 
        return bearerToken.substring(7, bearerToken.length());
    
    return null;


【问题讨论】:

您能详细说明发生了什么吗?当您尝试打开 localhost:8080/ 时失败了? 【参考方案1】:

您可能需要更多上下文,但这是一种可能的解决方案。

我认为可能发生的情况是,正如您告诉我们的那样,Spring 正在从静态文件夹 /static 提供您的内容(它甚至是默认的 Spring Boot 文件夹)。

但spring不知道它需要将请求从例如:localhost:8080/重定向到localhost:8080/index.html

注意:如果没有进一步的细节,很难理解可能发生的事情:)

【讨论】:

它在 localhost:8080/ 提供 index.html ,并为放置在同一目录中的其他 js 和 css 文件返回 403。 如果它服务正确并且你得到 403 似乎你的安全过滤器正在捕捉这些路径 如果不是/api/**,我建议忽略路径(假设你所有的api都在这个路径上)

以上是关于Spring Boot 2 和 Security With JWT 无法提供 Angular 构建的静态内容的主要内容,如果未能解决你的问题,请参考以下文章

spring boot spring-security-oauth2 默认的authorize和token接口的区别

Spring Boot 和 Spring Cloud Security OAUTH 2 SSO 在最新版本中失败

安全框架Spring Boot 整合 Spring Security

220.Spring Boot+Spring Security:自定义登录页面和构建主页

如何使用 Spring MVC & Security、Jasig CAS 和 JSP 视图在 Spring Boot 2 中配置 UTF-8?

在 Spring Security 5 OAuth Client 和 Spring Boot 2.0 中,authorizationGrantType 不能为空