java - 将 HTTP 替换为 HTTPS 后授权不起作用
问题描述
我用 spring-security 和 jwt 创建了一个应用程序。它运作良好。但这在我用 HTTPS 替换 HTTP 后不起作用。我已成功登录,但如果我使用任何 POST 请求到安全页面,则会收到 403 错误。其他请求(例如 GET)可以正常工作。
安全配置.java
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
public static final String USER_ROLE = "USER";
public static final String ADMIN_ROLE = "ADMIN";
@Autowired
private DataSource dataSource;
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOrigins(Arrays.asList("https://localhost:8888"));
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}
@Override
public void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.requiresChannel()
.anyRequest()
.requiresSecure();
httpSecurity.cors();
httpSecurity.csrf()
.ignoringAntMatchers("/login")
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
httpSecurity.requiresChannel().and().authorizeRequests()
.antMatchers("/recipe/add/**", "/comment/getModerate/**", "/recipe/changeRecipe/**")
.hasAnyRole(USER_ROLE, ADMIN_ROLE)
.antMatchers("/**")
.permitAll()
.and()
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
httpSecurity
.logout()
.logoutSuccessHandler(logoutHandler())
.deleteCookies("JSESSIONID", "COOKIE-BEARER")
.invalidateHttpSession(true)
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery("select username,password,enabled from users where username = ?")
.authoritiesByUsernameQuery("select rs.username, r.roles from users rs inner join user_role r on rs.id = r.role_id where rs.username = ?");
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
return encoder;
}
@Bean
public CustomLogoutSuccessHandler logoutHandler() {
return new CustomLogoutSuccessHandler();
}
}
JWTAuthenticationFilter.java
public class JWTAuthenticationFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException,
IOException {
try {
Authentication authentication = TokenAuthenticationHelper.getAuthentication(request);
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(request, response);
} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException |
SignatureException | IllegalArgumentException e) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token expired");
}
}
}
JWTLoginFilter.java
public class JWTLoginFilter extends AbstractAuthenticationProcessingFilter {
public JWTLoginFilter(String url, AuthenticationManager authManager) {
super(new AntPathRequestMatcher(url));
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws IOException {
AccountCredentials creds = new ObjectMapper().readValue(req.getInputStream(), AccountCredentials.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
creds.getAuthorities()
)
);
}
@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) {
TokenAuthenticationHelper.addAuthentication(res, auth);
}
static class AccountCredentials {
private String username;
private String password;
private Collection<GrantedAuthority> authorities;
String getUsername() {
return username;
}
void setUsername(String username) {
this.username = username;
}
String getPassword() {
return password;
}
void setPassword(String password) {
this.password = password;
}
Collection<GrantedAuthority> getAuthorities() {
return authorities;
}
void setAuthorities(Collection<GrantedAuthority> authorities) {
this.authorities = authorities;
}
}
}
TokenAuthenticationHelper.java
class TokenAuthenticationHelper {
private static final long EXPIRATION_TIME = 1000 * 60 * 60 * 3; // 3 hours
private static final String SECRET = "ThisIsASecret";
private static final String COOKIE_BEARER = "COOKIE-BEARER";
private TokenAuthenticationHelper() {
throw new IllegalStateException("Utility class");
}
static void addAuthentication(HttpServletResponse res, Authentication auth) {
String authorities = auth.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(","));
String jwt = Jwts.builder()
.setSubject(auth.getName())
.claim("authorities", authorities)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET)
.compact();
Cookie cookie = new Cookie(COOKIE_BEARER, jwt);
cookie.setHttpOnly(true);
cookie.setPath("/");
res.addCookie(cookie);
}
static Authentication getAuthentication(HttpServletRequest request) {
System.out.println(request);
Cookie cookie = WebUtils.getCookie(request, COOKIE_BEARER);
String token = cookie != null ? cookie.getValue() : null;
if (token != null) {
Claims claims = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
Collection<? extends GrantedAuthority> authorities =
Arrays.stream(claims.get("authorities").toString().split(","))
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
String userName = claims.getSubject();
return userName != null ? new UsernamePasswordAuthenticationToken(userName, null, authorities) : null;
}
return null;
}
}
服务器配置.java
@Configuration
public class ServerConfig {
@Bean
public ServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("ROLE_ADMIN");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(getHttpConnector());
return tomcat;
}
private Connector getHttpConnector() {
Connector connector = new Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL);
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8081);
return connector;
}
}
应用程序属性
server.port=8081
#server.ssl.key-store-type=PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=123456
server.ssl.key-alias=back
我认为问题出在 csrf 令牌上。我不能csrf().disable()
。你能帮我理解什么是错的吗?
解决方案
推荐阅读
- javascript - onclick 打开窗口和参考尺寸
- java - 为 Apache Storm 编写集成测试
- c# - 在 C# 中发送带有请求正文的 WebRequest GET
- java - 如何打印一行中第 N 个单词的第 N 个字符?
- laravel - 从 Laravel Blade 文件中导入一个 Vue js 组件
- r - 使用 ROI 进行投资组合优化
- javascript - PDFKit 渲染空白地图而不是传单地图
- angular - Angular 8,使用 jspdf 和 autotable-jspdf 导入/使用问题
- python - 将维度高度、宽度、通道数的图像转换为n_masks、image_height、image_width
- javascript - 在 datepicker jquery 中设置最大年份