Spring-boot: 将 Servlet Filter 应用到除一个之外的所有路由
Spring-boot: Apply Servlet Filter to all routes except one
spring-boot gurus 的问题!
用例:
我希望我的应用程序根据以下路由表现不同:
- / 不认证,不授权
- /
render
通过作为 URL 参数发送的 json 网络令牌 (jwt) 授权(我知道,这很奇怪)
- 任何其他途径:通过作为 URL 参数发送的 json 网络令牌 (jwt) 进行授权(我知道,这很奇怪)
jwt 的秘密存储为应用程序配置的一个元素 (application.yaml)(我知道这不是最佳实践,它是一个演示应用程序,所以我不关心)
我正在使用 SpringBoot 2.0.5
和 io.jsonwebtoken
作为 jwt 库。
我已经使用 Servlet Filter 实现了它,它可以工作,但感觉真的很丑。我找不到一种方法来说明“将此 Servlet 过滤器应用于除此列表 之外的所有端点”。我已将逻辑包含在 doFilter 方法中,但这 看起来真的很丑陋。
这个有'best practise'吗?
我目前的代码如下:
安全配置
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/render").permitAll()
.anyRequest().authenticated();
httpSecurity.headers().frameOptions().disable();
}
}
WebConfigurer
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;
@Configuration
public class WebConfigurer implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
initFilter(servletContext, disps);
}
private void initFilter(ServletContext servletContext,
EnumSet<DispatcherType> disps) {
FilterRegistration.Dynamic myFilter =
servletContext.addFilter("myFilter",
new JWTAuthenticationFilter());
myFilter.addMappingForUrlPatterns(disps, true, "/app/*");
myFilter.setAsyncSupported(true);
}
}
JWTAuthenticationFilter
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.impl.TextCodec;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JWTAuthenticationFilter extends GenericFilterBean {
@Value("${security.jwt.token.secret-key}")
private String secret;
@Override
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
String path = request.getRequestURI();
if (!path.equals("/")) {
String jwsString = request.getParameter("jwt");
Jws<Claims> jws;
String base64_encoded_secret = TextCodec.BASE64.encode(secret);
jws = Jwts.parser()
.setSigningKey(base64_encoded_secret)
.parseClaimsJws(jwsString);
}
} catch (Exception e) {
System.out.println(e);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed");
SecurityContextHolder.clearContext();
}
filterChain.doFilter(request, response);
}
}
找到解决方案!我使用了 FilterRegistrationBean。无法排除 URL。我的解决办法是把所有的app都放在app/目录下,这样我就不需要在根/上放一个过滤器了。
@Bean
public FilterRegistrationBean FilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(1);
registration.addUrlPatterns("/app/*");
return registration;
}
spring-boot gurus 的问题!
用例:
我希望我的应用程序根据以下路由表现不同:
- / 不认证,不授权
- /
render
通过作为 URL 参数发送的 json 网络令牌 (jwt) 授权(我知道,这很奇怪) - 任何其他途径:通过作为 URL 参数发送的 json 网络令牌 (jwt) 进行授权(我知道,这很奇怪)
jwt 的秘密存储为应用程序配置的一个元素 (application.yaml)(我知道这不是最佳实践,它是一个演示应用程序,所以我不关心)
我正在使用 SpringBoot 2.0.5
和 io.jsonwebtoken
作为 jwt 库。
我已经使用 Servlet Filter 实现了它,它可以工作,但感觉真的很丑。我找不到一种方法来说明“将此 Servlet 过滤器应用于除此列表 之外的所有端点”。我已将逻辑包含在 doFilter 方法中,但这 看起来真的很丑陋。
这个有'best practise'吗?
我目前的代码如下:
安全配置
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/render").permitAll()
.anyRequest().authenticated();
httpSecurity.headers().frameOptions().disable();
}
}
WebConfigurer
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Configuration;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.EnumSet;
@Configuration
public class WebConfigurer implements ServletContextInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
initFilter(servletContext, disps);
}
private void initFilter(ServletContext servletContext,
EnumSet<DispatcherType> disps) {
FilterRegistration.Dynamic myFilter =
servletContext.addFilter("myFilter",
new JWTAuthenticationFilter());
myFilter.addMappingForUrlPatterns(disps, true, "/app/*");
myFilter.setAsyncSupported(true);
}
}
JWTAuthenticationFilter
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.impl.TextCodec;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JWTAuthenticationFilter extends GenericFilterBean {
@Value("${security.jwt.token.secret-key}")
private String secret;
@Override
public void doFilter(ServletRequest req,
ServletResponse res,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
try {
String path = request.getRequestURI();
if (!path.equals("/")) {
String jwsString = request.getParameter("jwt");
Jws<Claims> jws;
String base64_encoded_secret = TextCodec.BASE64.encode(secret);
jws = Jwts.parser()
.setSigningKey(base64_encoded_secret)
.parseClaimsJws(jwsString);
}
} catch (Exception e) {
System.out.println(e);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication failed");
SecurityContextHolder.clearContext();
}
filterChain.doFilter(request, response);
}
}
找到解决方案!我使用了 FilterRegistrationBean。无法排除 URL。我的解决办法是把所有的app都放在app/目录下,这样我就不需要在根/上放一个过滤器了。
@Bean
public FilterRegistrationBean FilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(1);
registration.addUrlPatterns("/app/*");
return registration;
}