I have a problem when using spring security in a vaadin project with spring-boot. So I'am using a PdfViewer Addon to display PDF Files. But I'm getting the following error message:
error:"Not Found"
message:"No message available"
path:"/APP/PUBLISHED/pdf.worker.js"
status:404
and my spring security configuration looks like this:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.frameOptions().sameOrigin().and()
.csrf().disable() // Use Vaadin's CSRF protection
.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/vaadinServlet/HEARTBEAT/**").permitAll()
.antMatchers("/vaadinServlet/UIDL/**").permitAll()
.antMatchers("/vaadinServlet/APP/PUBLISHED/**").permitAll()
.antMatchers("login?debug").permitAll()
.antMatchers("/#!pwdreset/*").permitAll()
.antMatchers("/pwdreset/*").permitAll()
.and()
.authorizeRequests()
.and()
.formLogin().loginPage("/#!login").permitAll()
.and()
.logout().logoutUrl("/#!login?logout").logoutSuccessUrl("/").permitAll().and()
.sessionManagement().sessionFixation().newSession();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**", "/VAADIN/**");
}
So checking the loaded files in Chrome I see a folder /vaadinServlet/APP/PUBLISHED/ and there are all the files needed.
Using the Addon without Spring Security works fine, so anyone any idea?
Update
It doesn't seem to be related to spring security, because I get a similar behavior while testing the Addon in a new simple project. It seems to be a problem with spring boot.
To reproduce this issue you need ( full project for download ):
/webapp/files
@Theme("mytheme")
@SpringUI
@Widgetset("org.test.AppWidgetSet")
public class MyUI extends UI {
@Override
protected void init(VaadinRequest vaadinRequest) {
final VerticalLayout layout = new VerticalLayout();
String basepath = VaadinService.getCurrent().getBaseDirectory().getAbsolutePath();
File file = new File(basepath.concat("/files/test.pdf"));
if (file.exists()) {
PdfViewer pdfViewer = new PdfViewer(file);
Label info = new Label("File was found!");
layout.addComponents(info, pdfViewer);
} else {
Label info = new Label("no file found!");
layout.addComponent(info);
}
setContent(layout);
}
}
Network
tab selected, access the app and you should see one request for pdf.worker.js
fail. TL;DR; version:
A second request is being triggered by pdf.js
to download pdf.worker.js
, but it does not match the path /vaadinServlet/APP/PUBLISHED/pdf.worker.js
handled by the auto-configured VaadinServlet
, it's just /APP/PUBLISHED/pdf.worker.js
.
The simplest solution I could come up with, is a controller which forwards the request to the VaadinServlet
:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PdfJsRedirectController {
private static final String WORKER_JS_INCORRECT_PATH = "/APP/PUBLISHED/pdf.worker.js";
private static final String WORKER_JS_CORRECT_FORWARD_PATH = "forward:/vaadinServlet/APP/PUBLISHED/pdf.worker.js";
@RequestMapping(value = WORKER_JS_INCORRECT_PATH)
public String forwardWorkerJsRequestToVaadin() {
return WORKER_JS_CORRECT_FORWARD_PATH;
}
}
Detailed version:
So, I've spent some time debugging this, and it turns out to be a combination of unfortunate configs:
What happens is, spring registers a DispatcherServlet
serving requests for /*
. and Vaadin registers a VaadinSpringServlet
for the /vaadinServlet/*
& /VAADIN
paths:
ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
ServletRegistrationBean : Mapping servlet: 'springVaadinServlet' to [/vaadinServlet/*, /VAADIN/*]
To co-exist with the dispatcher servlet and be able to serve requests also on "/*", Vaadin also registers a forwarding-controller for the UI
paths. For example requests on /MyUI
will be forwarded to /vaadinServlet/MyUI
(see the VaadinServletConfiguration
sources for more details).
Until now everything works fine and you should not have any issues. Just like you said, looking at the chrome dev-tools all the js
files are there, so what's wrong? If you look closley at the requests made when you access your app, you'll notice that actually there are 2 requests for pdf.worker.js
- the first one that is successful, and the one which gives you the 404:
The Initiator
column for the the call that fails, is actually pdf.js:2344
and if you set a breakpoint you can actually see that workerSrc=/APP/PUBLISHED/pdf.worker.js
, value which is defined in pl.pdfviewer.client.ui.PdfViewer.java
. You may have to scroll horizontally a bit to be able to see the code, so I've formatted it below:
public native void loadResourcePdf(String fileName, VPdfViewer instance)/*-{
var pdfviewer = instance.@pl.pdfviewer.client.ui.VPdfViewer::jsObject;
pdfviewer.work = false;
if ((pdfviewer.fileName == null || pdfviewer.fileName != fileName) && fileName != null) {
$wnd.PDFJS.disableStream = true;
======> $wnd.PDFJS.workerSrc = 'APP/PUBLISHED/pdf.worker.js';
$wnd.PDFJS.getDocument(fileName).then(function (pdf) {
pdfviewer.pdfFile = pdf;
pdfviewer.fileName = fileName;
pdfviewer.pageCount = pdf.numPages;
if (pdfviewer.pageNumber == 0 && pdf.numPages > 0) {
pdfviewer.pageNumber = 1;
}
pdfviewer.showPdfPage(pdfviewer.pageNumber);
});
}
}-*/;
In a regular Vaadin environment, /APP/PUBLISHED/pdf.worker.js
would work out of the box, but we're now in a slightly altered one so we need some adjustments. Bottom line, we can use a similar approach to what Vaadin auto-configuration is doing, and redirect the /APP/PUBLISHED/pdf.worker.js
request to /vaadinServlet/APP/PUBLISHED/pdf.worker.js
and finally overcome the issue. For the sake of brevity, the redirect controller can be seen at the beginning of this post.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.