Home  >  Q&A  >  body text

After successful login, Spring Boot Thymeleaf implements the file download function

I want to provide a web service with Spring Boot that is able to download dumps from a MySQL database.

But downloading shouldn't be suitable for everyone. So I need a kind of login. Not quite sure where the credentials will be stored, it's possible they are just hardcoded in the application itself.

I'm a bit lost and don't know how to implement this.

This is what I've got so far:

@Controller
public class EBMysqldumpController {

    private EBMysqldumpService mysqldumpService;

    @Autowired
    public EBMysqldumpController(EBMysqldumpService mysqldumpService) {
        this.mysqldumpService = mysqldumpService;
    }

    @GetMapping("/login")
    public String showLoginForm(Model model) {
        model.addAttribute("userDto", new UserDto());
        return "mysqldump-login";
    }

    @PostMapping(path = "/login")
    public String validateLoginForm(@Valid UserDto userDto, BindingResult result, HttpServletRequest request) {
        if (result.hasErrors()) {
            return "mysqldump-login";
        }

        if (!this.mysqldumpService.checkLogin(userDto)) {
            result.addError(new ObjectError("", "Wrong username and/or password"));
            return "mysqldump-login";
        }

        return "redirect:/file";
    }

    @PostMapping(path = "/file")
    public ResponseEntity<Resource> startMysqlDump(@Valid UserDto userDto, Model model) throws IOException, InterruptedException, MysqldumpException {
        if (!this.mysqldumpService.checkLogin(userDto)) {
            return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
        }

        File mysqlDump = this.mysqldumpService.getMysqlDumpFile();
        ByteArrayResource byteArrayResource = this.mysqldumpService.getByteArrayResourceFromFile(mysqlDump);

        HttpHeaders headers = getMysqldumpHeaders(mysqlDump.getName());
        ResponseEntity<Resource> body = ResponseEntity.ok()
                .headers(headers)
                .contentLength(mysqlDump.length())
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(byteArrayResource);

        this.mysqldumpService.deleteFile(mysqlDump);

        return body;
    }

    private HttpHeaders getMysqldumpHeaders(String filename) {
        ContentDisposition contentDisposition = ContentDisposition.inline().filename(filename).build();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentDisposition(contentDisposition);

        return headers;
    }

}

Currently the controller displays the login page at "/login". After submitting the form, the controller checks if the credentials are correct and if not, displays the login page again with an error message.

But my problem is, I don't know what to do after logging in successfully. The download works fine when I call it directly, but it doesn't work when using a redirect because I make a post request to ensure that the user who just logged in can download the file. If I make a get request, everyone can use the link.

I have a feeling that the way I'm approaching the problem is wrong. What would you recommend? How to start downloading after successful login?

P粉957661544P粉957661544205 days ago317

reply all(1)I'll reply

  • P粉574695215

    P粉5746952152024-03-29 00:48:53

    I recommend adding Spring Security to your project and having a hardcoded user in it:

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    @Configuration
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .passwordEncoder(passwordEncoder)
                .withUser("user1").password("my-secret-pwd").roles("USER");
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests(
                        registry -> registry.mvcMatchers("/**").authenticated()
                )
                .formLogin();
        }
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return NoOpPasswordEncoder.getInstance();
        }
    }

    reply
    0
  • Cancelreply