405 方法不允许,弹簧启动,但我使用了 csrf 令牌头
Posted
技术标签:
【中文标题】405 方法不允许,弹簧启动,但我使用了 csrf 令牌头【英文标题】:405 Method Not Allowed, spring boot, but i used csrf token header 【发布时间】:2021-03-14 00:26:34 【问题描述】:我正在使用 Spring Boot 制作 Web 应用程序服务器。
在开发初期,我使用了http.csrf().disable()
的设置,网页运行良好。
但是自从禁用设置被删除后,错误只发生在host address page。当我请求 GET 时,它完全可以正常工作,但是,它不适用于 POST、PUT、DELETE...当我在本地主机上进行测试时,所有请求都可以正常工作,包括这些方法。
我已经使用了 csrf 令牌标头、表单的隐藏 csrf 输入以及在 ajax 中设置 csrf 标头的beforeSend
。我什至更改了 nginx 设置 (error_page 405 =200 $uri;
),但它保持不变。
这是我的环境。
jdk 11 春天 2.3.5 AWS EC2 - Amazon Linux 2 AMI AWS RDS - PostgreSQL 13 AWS S3 Nginx 1.18.0 毕业 5.6.4 百里香
请问有人可以帮我吗?
My Github Repository Link
# aws server- nohup.out
[ec2-user@teamcoder-webservice ~]$ vim ~/app/step3/nohup.out
2020-12-01 23:24:18.953 INFO 3697 --- [ main] o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any request, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3ad85136, org.springframework.security.web.context.SecurityContextPersistenceFilter@2bc426f0, org.springframework.security.web.header.HeaderWriterFilter@176f7f3b, org.springframework.security.web.csrf.CsrfFilter@7d3c09ec, org.springframework.security.web.authentication.logout.LogoutFilter@1f53481b, org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@7f93dd4e, org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter@5ad5be4a, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@33425811, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@4cb2918c, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@737d100a, org.springframework.security.web.session.SessionManagementFilter@58740366, org.springframework.security.web.access.ExceptionTranslationFilter@4af45442, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@671c4166]
2020-12-01 23:24:20.068 INFO 3697 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2020-12-01 23:24:20.550 INFO 3697 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
2020-12-01 23:24:20.552 INFO 3697 --- [ main] DeferredRepositoryInitializationListener : Triggering deferred initialization of Spring Data repositories…
2020-12-01 23:24:21.474 INFO 3697 --- [ main] DeferredRepositoryInitializationListener : Spring Data repositories initialized!
2020-12-01 23:24:21.499 INFO 3697 --- [ main] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
2020-12-01 23:24:21.527 INFO 3697 --- [ main] c.j.team.teamcoder.TeamCoderApplication : Started TeamCoderApplication in 17.806 seconds (JVM running for 19.458)
2020-12-01 23:24:23.438 INFO 3697 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-12-01 23:24:23.443 INFO 3697 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-12-01 23:24:23.460 INFO 3697 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 17 ms
2020-12-02 03:05:22.223 WARN 3697 --- [nio-8081-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
# /etc/nginx/nginx.conf
http
...
server
listen 80;
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
include /etc/nginx/conf.d/service-url.inc;
location /
limit_except GET POST PUT DELETE
deny all;
proxy_pass $service_url;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
error_page 405 =200 $uri;
error_page 404 /404.html;
location = /40x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html
#after change upper configuration
[ec2-user@teamcoder-webservice nginx]$ sudo /usr/sbin/nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
另外,以下代码是java spring boot代码。
<!--ajax non-used request in "user_info.html"-->
<form th:action="@'/api/v1/user/pic/' + $user.id" method="post" enctype="multipart/form-data" name="pictureForm">
<table>
<tr><td><label th:for="picture">Profile Image</label></td>
<td><input type="file" id="picture" name="picture" accept="image/png, image/jpeg" /></td></tr>
<tr><td><img th:src="@$user.picture" id="picture_img" ></td>
<td><input type="button" name="Upload" value="Upload" onclick="submit_file_form(document.forms['pictureForm'].picture, 'pictureForm');" class="btn btn-info"/></td></tr>
</table>
<input type="hidden" name="pastPath" id="pastPath" th:value="$user.picture"/>
<input type="hidden" th:name="$_csrf.parameterName" th:value="$_csrf.token" />
</form>
//ajax used request in "user_info.html" -> "userInfo.js"
...
const csrfToken = $('#_csrf').attr('content');
const csrfHeader = $('#_csrf_header').attr('content');
var user_info =
init : function ()
var _this = this;
$('#btn-update').on('click', function ()
_this.update();
);
$('#btn-delete').on('click', function ()
_this.delete();
);
,
update : function ()
var data =
name: $('#name').val(),
tags: commaToArray(convertTags($('#tags').val())),
email: $('#email').val(),
birth: $('#birth').val(),
education: $('#education').val().toUpperCase(),
location: $('#location').val()
;
var id = $('#id').val();
$.ajax(
type: 'PUT',
url: '/api/v1/user/'+id,
dataType: 'json',
contentType:'application/json; charset=utf-8',
data: JSON.stringify(data),
beforeSend: function (xhr)
xhr.setRequestHeader(csrfHeader, csrfToken);
).done(function()
alert('your information is modified');
window.location.href = '/';
).fail(function (error)
alert(JSON.stringify(error));
);
,
...
<!-- in html header -->
<meta id="_csrf" th:name="$_csrf.parameterName" th:content="$_csrf.token"/>
<meta id="_csrf_header" name="_csrf_header" th:content="$_csrf.headerName"/>
@RequiredArgsConstructor
@RestController
public class UserApiController
private final UserService userService;
private final RoleService roleService;
@PutMapping("/api/v1/user/id")
public Long update(@PathVariable String id,
@RequestBody UserUpdateRequestDto requestDto)
roleService.reloadRolesForAuthenticatedUser(Role.USER.getKey());
return userService.update(Long.valueOf(id), requestDto);
@RequiredArgsConstructor
@RestController
public class FileController
private final UserService userService;]
private final S3Service s3Service;
@PostMapping("/api/v1/user/pic/id")
public String updateUserPic(@PathVariable String id,
@RequestParam("pastPath") String pastPath,
@RequestPart("picture") MultipartFile multipartFile) throws IOException
String uploadDir = s3Service.upload(pastPath, multipartFile,"users/");
userService.updatePic(Long.valueOf(id), uploadDir);
return "You successfully uploaded " + uploadDir + "!";
//SecurityConfig.java
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
private final CustomOAuth2UserService customOAuth2UserService;
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring().antMatchers("/css/**", "/js/**", "/assets/img/**", "/lib/**", "/user-photos/**", "/group-files/**");
@Override
protected void configure(HttpSecurity http) throws Exception
http.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.authorizeRequests()
.antMatchers("/", "/logoption","/user/denied", "/search/**", "/privacy/rule","/profile").permitAll()
.antMatchers("/api/v1/user/**", "/api/v1/**").hasRole("GUEST")
.antMatchers("/api/v1/group/**", "/group/**", "/api/v1/participate/**").hasRole("USER")
.anyRequest().authenticated()
.and()
.logout().logoutSuccessUrl("/")
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.and()
.exceptionHandling()
.accessDeniedPage("/user/denied")
.and()
.oauth2Login()
.loginPage("/logoption")
.defaultSuccessUrl("/")
.userInfoEndpoint()// after oauth2 login
.userService(customOAuth2UserService);
//for Spring Security
@Bean
public ServletListenerRegistrationBean<HttpSessionEventPublisher> httpSessionEventPublisher()
return new ServletListenerRegistrationBean<>(new HttpSessionEventPublisher());
【问题讨论】:
【参考方案1】:尝试将这些添加到您的 SecurityConfig 中:
http.cors().and()....
以及 CORS 配置:
@Bean
public CorsFilter corsFilter()
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("*"); // TODO: lock down before deploying
config.addAllowedHeader("*");
config.addExposedHeader(HttpHeaders.AUTHORIZATION);
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
【讨论】:
以上是关于405 方法不允许,弹簧启动,但我使用了 csrf 令牌头的主要内容,如果未能解决你的问题,请参考以下文章
尽管以表单形式发送 CSRF 令牌,但不支持 Spring Security CSRF 405 方法 POST