【问题标题】:Problem with integration vaadin view in JSP applicationJSP应用程序中集成vaadin视图的问题
【发布时间】:2020-01-04 07:45:14
【问题描述】:

当我已经将 JSP 用于我的登录/注册表单时,我在我的 Spring MVC 应用程序中使用了 vaadin。我有问题,也许 WebSecurity 没有为我的 vaadin 视图提供 POST 方法。 我想在成功通过身份验证的用户后返回带有一个组件的 vaadin 视图。 不知道哪里出了问题。

将 JSP 与 vaadin 集成可能很奇怪,但我认为这很简单

配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig  extends WebSecurityConfigurerAdapter {

private UserDetailsServiceImpl userDetailsService;
private AppUserRepo appUserRepo;


@Autowired
public WebSecurityConfig(UserDetailsServiceImpl userDetailsService, AppUserRepo appUserRepo) {
    this.userDetailsService = userDetailsService;
    this.appUserRepo = appUserRepo;
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
            .antMatchers("/admin").hasRole("ADMIN")
            .antMatchers("/user").hasAnyRole("ADMIN", "USER")
            .antMatchers("/upload").hasRole("ADMIN")
            .antMatchers("/gallery").hasRole("ADMIN")
            .and()
            .csrf().disable()
            .formLogin().loginPage("/login").permitAll()
            .and()
            .logout().permitAll();
}

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers(
            // Vaadin Flow static resources //
            "/VAADIN/**",

            // the standard favicon URI
            "/favicon.ico",

            // the robots exclusion standard
            "/robots.txt",

            // web application manifest //
            "/manifest.webmanifest",
            "/sw.js",
            "/offline-page.html",

            // (development mode) static resources //
            "/frontend/**",

            // (development mode) webjars //
            "/webjars/**",

            // (production mode) static resources //
            "/frontend-es5/**", "/frontend-es6/**");
}

@Bean
public PasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
}

@Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
    return authenticationManager();
}

@EventListener(ApplicationReadyEvent.class)
public void get(){
    AppUser appUserUser = new AppUser("jan", passwordEncoder().encode("jan"),"ROLE_USER");
    AppUser appUserAdmin = new AppUser("admin", passwordEncoder().encode("admin"),"ROLE_ADMIN");
    appUserRepo.save(appUserUser);
    appUserRepo.save(appUserAdmin);
}
}

控制器:

@Controller
public class UserFormController {
@Autowired
private RegistrationService registrationService;

@Autowired
private SecurityService securityService;

@Autowired
private UserValidator userValidator;

@RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registration(Model model) {
    model.addAttribute("userForm", new AppUser());

    return "/registration.jsp";
}

@RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(@ModelAttribute("userForm") AppUser userForm, BindingResult bindingResult, Model model) {
    userValidator.validate(userForm, bindingResult);

    if (bindingResult.hasErrors()) {
        return "/registration.jsp";
    }

   registrationService.save(userForm);
   securityService.autoLogin(userForm.getUsername(), userForm.getPassword());

    return "redirect:/welcome.jsp";
}

@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(Model model, String error, String logout) {
    if (error != null)
        model.addAttribute("error", "Your username and password is invalid.");

    if (logout != null)
        model.addAttribute("message", "You have been logged out successfully.");

    return "/login.jsp";
}

@RequestMapping(value = {"/", "/welcome"}, method = RequestMethod.GET)
public String welcome(Model model) {
    return "upload";
}
}

Vaadin 视图:

@Route("upload")
public class UploadGui extends VerticalLayout{

private ImageUploader imageUploader;
private ByteConverter byteConverter;

@Autowired
public UploadGui(ImageUploader imageUploader, ByteConverter byteConverter) {
    this.byteConverter = byteConverter;
    this.imageUploader = imageUploader;

    MultiFileMemoryBuffer buffer = new MultiFileMemoryBuffer();
    Upload upload = new Upload(buffer);

    upload.addSucceededListener(event -> {
        byteConverter.byteArrayToFile(buffer.getOutputBuffer(event.getFileName()), event);
        imageUploader.uploadFile(new File(event.getFileName()));
    });

    add(upload);
}
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<c:set var="contextPath" value="${pageContext.request.contextPath}"/>

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="utf-8">
      <title>Log in with your account</title>

      <link href="${contextPath}/resources/css/bootstrap.min.css" rel="stylesheet">
      <link href="${contextPath}/resources/css/common.css" rel="stylesheet">
  </head>

  <body>

    <div class="container">
      <form method="POST" action="${contextPath}/login" class="form-signin">
        <h2 class="form-heading">Log in</h2>

        <div class="form-group ${error != null ? 'has-error' : ''}">
            <span>${message}</span>
            <input name="username" type="text" class="form-control" placeholder="Username"
                   autofocus="true"/>
            <input name="password" type="password" class="form-control" placeholder="Password"/>
            <span>${error}</span>
            <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>

            <button class="btn btn-lg btn-primary btn-block" type="submit">Log In</button>
            <h4 class="text-center"><a href="${contextPath}/registration">Create an account</a></h4>
        </div>
      </form>
    </div>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script src="${contextPath}/resources/js/bootstrap.min.js"></script>
  </body>
</html>

属性:

spring.jpa.hibernate.ddl-auto=create
spring.servlet.multipart.enabled=false
spring.jpa.show-sql=true
spring.messages.basename=validation

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.6.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>photouploader</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>photouploader</name>
<description>web uploader for photos</description>

<properties>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.cloudinary/cloudinary-core -->
    <dependency>
        <groupId>com.cloudinary</groupId>
        <artifactId>cloudinary-core</artifactId>
        <version>1.22.1</version>
    </dependency>
    <dependency>
        <groupId>com.cloudinary</groupId>
        <artifactId>cloudinary-http44</artifactId>
        <version>RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.vaadin/vaadin-spring-boot-starter -->
    <dependency>
        <groupId>com.vaadin</groupId>
        <artifactId>vaadin-spring-boot-starter</artifactId>
        <version>13.0.11</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper -->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <version>9.0.24</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

当我打开“localhost:8080/upload”时,我得到了那个日志:

`Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]`

在浏览器中我看到了

Server connection lost, trying to reconnect...

我认为 csrf.disable() 只是解决问题,但问题是另一个问题。

也许你解释一下?

也许一些 web.xml 配置?

【问题讨论】:

    标签: java spring model-view-controller vaadin


    【解决方案1】:

    我认为您可能缺少 Vaadin 内部请求的安全配置。这些用于前端和后端之间的通信。查看this tutorialisFrameworkInternalRequest 部分。

    【讨论】:

    • 好的,我没有解决 JSP 与 Vaadin 集成的问题。我只使用 Vaadin 而不是 JSP,我的问题就消失了。对于未来的旅行者,我不建议将 vaadin 和 JSP 都与 Spring Security 一起使用。它很难使用和实施,有时甚至无法处理。