环境:Springboot2.4.12+SpringSecurity5.4.9本文主要内容是基于内存配置引入依赖org.springframework.bootspring-boot-starter-security自定义用户配置spring:security:user:name:adminpassword:123456defineControllerinterface@RestController@RequestMapping("/demos")publicclassDemoController{@GetMapping("home")publicObjecthome(){return"demoshome";}}访问:http://localhost:8080/demos/home。会自动跳转到默认的登录页面:使用配置文件中配置的admin/123123登录,再定义一个POST接口就没有问题了。@PostMapping("post")publicObjectpost(){return"demospost";}注意:这里我们使用Postman访问默认登录/登录界面先登录,登录后访问post界面。(记住我们上面访问的GET/demos/home接口,只要你登录了就可以继续访问这个接口)。首次登录时,注意返回登录页面的html内容。表单信息中有一个隐藏域_csrf字段。如果我们通过Postman模拟登录,没有这个字段就无法登录。修改登录信息添加_csrf表单域,然后登录。这里返回404状态码是因为我们没有配置默认的登录成功页面。现在,在Postman中登录成功了。接下来我们继续通过Postman访问GET/demos/home接口。直接访问没有问题,然后访问上面定义的POST/demos/post接口。服务器返回403AccessDenied。上面的GET方法是正常的,但是POST出现异常,然后我们在登录的时候提交上面的_csrf字段,POST请求必须携带正确的_csrf信息才能继续这个方法。实现原理默认情况下,Security会添加一个CsrfFilter过滤器。publicfinalclassCsrfFilterextendsOncePerRequestFilter{protectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainfilterChain)throwsServletException,IOException{//从默认的HttpSessionCsrfTokenRepository中获取token,默认是从session中CsrftokenToken=this.srfToken);布尔missingToken=(csrfToken==null);if(missingToken){//如果当前会话不存在则生成令牌csrfToken=this.tokenRepository.generateToken(request);//如果csrfToken不为空,那么这里什么都不做不要做(不会保存)this.tokenRepository.saveToken(csrfToken,request,response);}//...//判断当前请求方法是否为("GET","HEAD","TRACE","OPTIONS")//如果是上面的Method,则直接放行,否则继续执行如果(!this.requireCsrfProtectionMatcher.matches(request)){filterChain.doFilter(request,response);返回;}//从请求头中获取_csrf值,headerName=X-CSRF-TOKENStringactualToken=request.getHeader(csrfToken.getHeaderName());if(actualToken==null){//如果header不存在,从请求参数中获取parameterName=_csrfactualToken=request.getParameter(csrfToken.getParameterName());}//判断当前参数中的token如果值不等于当前session中保存的,返回403错误if(!equalsConstantTime(csrfToken.getToken(),actualToken)){?新的InvalidCsrfTokenException(csrfToken,actualToken):newMissingCsrfToken(actualToken);this.accessDeniedHandler.handle(请求,响应,异常);返回;}filterChain.doFilter(请求,响应);}}一般我们会关闭csrffunction@ConfigurationpublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@Overrideprotected(voHttpSecurityhttp)throwsException{//关闭csrf就是删除CsrfFilter过滤器。http.csrf().disable();//拦截任何请求http.authorizeRequests().anyRequest().authenticated();//这里需要加上这句话,否则不会出现登录页面http.formLogin();}}以上是SpringSecurity默认配置情况下csrf相关问题。接下来通过自定义类配置设置用户的用户信息。自定义配置@ConfigurationpublicclassSecurityConfigextendsWebSecurityConfigurerAdapter{@SuppressWarnings("deprecation")@Overrideprotectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{//后续文章会介绍。//super.configure(auth);//配置用户名密码角色,以及密码编码方式auth.inMemoryAuthentication().passwordEncoder(NoOpPasswordEncoder.getInstance()).withUser("guest").password("123456").roles("ADMIN");}@Overrideprotectedvoidconfigure(HttpSecurityhttp)throwsException{http.csrf().disable();http.authorizeRequests().anyRequest().authenticated();http.formLogin();}}通过以上配置后,授权时需要使用这里的配置信息。本文介绍到这里,下篇文章将介绍具体的请求拦截配置和自定义登录页面等功能更新。