简体   繁体   中英

Production environment: Spring security login success redirect to localhost

I use Spring Boot 2.1.6.RELEASE, Apache 2.7

<VirtualHost demo.example.com:80>
    ProxyPass / "http://localhost:8081/"
    ServerName demo.example.com
    ProxyPassReverse / http://127.0.0.1:8081/
</VirtualHost>

Spring Securit config

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.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;
import java.util.List;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    FunctionPathRepository functionPathRepository;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    @Autowired
    private DataSource dataSource;

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

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        // Set service for searching user in database. And set password_encoder.
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();

        // Pages no need login request.
        http.authorizeRequests().antMatchers("/", "/login", "/logout", "/images", "/css", "/js").permitAll();

        // Trang /userInfo yêu cầu phải login với vai trò ROLE_USER hoặc ROLE_ADMIN.
        // Nếu chưa login, nó sẽ redirect tới trang /login.
        http.authorizeRequests().antMatchers("/userInfo").access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')");

        // Page for admin only.
        http.authorizeRequests().antMatchers("/admin").access("hasRole('ROLE_ADMIN')");


        List<FunctionPath> functionPathList = functionPathRepository.findAllByRole("CHIEF_ACCOUNTANT");
        int size = functionPathList.size();
        String[] functionPathArray = new String[size];
        for(int i = 0; i < size; i++){
            functionPathArray[i] = functionPathList.get(i).getFunctionPath();
        }
        http.authorizeRequests().antMatchers(functionPathArray).access("hasRole('ROLE_ADMIN')");
http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/403");

        // Configuration for login form.
        http.authorizeRequests().and().formLogin()
                .loginProcessingUrl("/j_spring_security_check") // Submit URL of Login page.
                .loginPage("/login")
                //.defaultSuccessUrl("/userAccountInfo")
                .defaultSuccessUrl("/desktop")

                .failureUrl("/login?error=true")
                .usernameParameter("username")
                .passwordParameter("password")
                // Configuration for logout page.
                .and().logout().logoutUrl("/logout")
                // .logoutSuccessUrl("/logoutSuccessful")
                .logoutSuccessUrl("/login")

        ;
        // Configuration for Remember me function (remember 24h).
        http.authorizeRequests().and().rememberMe().tokenRepository(this.persistentTokenRepository()).tokenValiditySeconds(1 * 24 * 60 * 60);
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }

}

Controller

/**
 * Show desktop.
 *
 * @return
 */
@RequestMapping(value = "/desktop", method = RequestMethod.GET)
public ModelAndView desktop() {
    ModelAndView modelAndView = new ModelAndView("system/desktop");
    modelAndView.getModel().put("page_title", "Bàn làm việc");
    return modelAndView;
}

I run

java -jar accounting-2019.07-SNAPSHOT.jar

Step 1. Go to http://demo.example.com/

Step 2. Login success

Step 3. The web-app redirect to http://localhost:8081/desktop , then the webapp fail.

How to redirect to http://demo.example.com/desktop ?

The solution is to:

  1. Foward the original protocol, host and port to your Spring Boot application (partially in additional HTTP headers, partially in the regular HTTP header attributes)

  2. Configure Spring Boot to evaluate this information

Typically it's done with the following configuration:

Apache configuration

Add the ProxyPreserveHost and ProxyPreserveHost directives:

<VirtualHost demo.bkit.vn:80>
    ProxyPreserveHost on
    RequestHeader set X-Forwarded-Proto http
    RequestHeader set X-Forwarded-Port 80
    ProxyPass / "http://localhost:8081/"
    ServerName demo.example.com
    ProxyPassReverse / http://127.0.0.1:8081/
</VirtualHost>

Spring Boot configuraiton

In the Spring Boot configuration (eg application.properties ), add the following line:

server.use-forward-headers=true

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM