복붙노트

[SPRING] 스프링 보안 4 사용자 정의 로그인 j_spring_security_check은 http 302를 반환합니다.

SPRING

스프링 보안 4 사용자 정의 로그인 j_spring_security_check은 http 302를 반환합니다.

나는 최신 스프링 프레임 워크, 코드 기반 컨피규레이션에 관한 질문을했다.

이니셜 라이저

public class AppInitializer extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { SecurityConfig.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { MvcConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

mvc config

    @EnableWebMvc
    @ComponentScan({ "com.appname.controller" })
    public class MvcConfig extends WebMvcConfigurerAdapter {
        @Bean
        public InternalResourceViewResolver viewResolver() {
            InternalResourceViewResolver resolver = new InternalResourceViewResolver();
            resolver.setPrefix("/WEB-INF/jsp/");
            resolver.setSuffix(".jsp");
            return resolver;
        }

@Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/res/**").addResourceLocations("/res/");
    }
    }

보안 설정

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private CustomUserDetailsService customUserDetailsService;

public SecurityConfig() {
    customUserDetailsService = new CustomUserDetailsService();
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
        throws Exception {
    auth.inMemoryAuthentication().withUser("user").password("password")
            .roles("USER");
    auth.userDetailsService(customUserDetailsService);
}

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/res/**").permitAll()
            .and().authorizeRequests()
            .anyRequest().hasRole("USER")
            .and().formLogin().loginPage("/account/signin").permitAll()
            .and().logout().permitAll();
    }
}

보안 이니셜 라이저

public class SecurityInitializer extends
        AbstractSecurityWebApplicationInitializer {

}

사용자 정의 로그인

public class CustomUserDetailsService implements UserDetailsService {

    private AccountRepository accountRepository;

    public CustomUserDetailsService() {
        this.accountRepository = new AccountRepository();
    }

    @Override
    public UserDetails loadUserByUsername(String email)
            throws UsernameNotFoundException {

        Account account = accountRepository.getAccountByEmail(email);

        if (account == null) {
            throw new UsernameNotFoundException("Invalid email/password.");
        }

        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("USER"));

        return new User(account.getEmail(), account.getPassword(), authorities);
    }
}

그러나 이제 사용자 정의 로그인에 대한 새로운 문제가 있습니다.

j_spring_security_check에 게시 할 때 http 302를 받게됩니다.

/을 (를) 요청했지만 로그인 한 후 로그인 페이지에 머물러 있습니다.

스프링 보안 4.x 버전과 순전히 코드 기반 구성을 사용하고 있으므로 인터넷에서 더 많은 참조를 찾을 수 없습니다. 아무도 이유를 알아낼 수 있습니다.

편집하다

org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'securityConfig': 
Injection of autowired dependencies failed; 
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: 
private org.springframework.security.core.userdetails.UserDetailsService sg.mathschool.infra.SecurityConfig.userDetailsService; 
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: 
No qualifying bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: 
expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=userDetailsService)}

CustomUserDetailsService를 변경했습니다.

@Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {

    private AccountRepository accountRepository;

    public CustomUserDetailsService() {
        this.accountRepository = new AccountRepository();
    }

    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String email)
            throws UsernameNotFoundException {

        Account account = accountRepository.getAccountByEmail(email);

        if (account == null) {
            throw new UsernameNotFoundException("Invalid email/password.");
        }

        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority("USER"));

        return new User(account.getEmail(), account.getPassword(), authorities);
    }
}

및 보안 구성

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier("userDetailsService")
    private UserDetailsService userDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.inMemoryAuthentication().withUser("user").password("password")
                .roles("USER");
        auth.userDetailsService(userDetailsService).passwordEncoder(
                passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/res/**").permitAll()
                .antMatchers("/account/**").permitAll().anyRequest()
                .hasRole("USER").and().formLogin().loginPage("/account/signin")
                .failureUrl("/account/signin?error").usernameParameter("email")
                .passwordParameter("password").and().logout()
                .logoutSuccessUrl("/account/signin?logout").and().csrf();

    }

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

해결법

  1. ==============================

    1.스프링 보안 4.x 로그인 URL이 j_spring_security_check 대신 로그인으로 변경되었습니다. 스프링 보안 3.x에서 4.x로 마이그레이션 (XML 구성)을 참조하십시오.

    스프링 보안 4.x 로그인 URL이 j_spring_security_check 대신 로그인으로 변경되었습니다. 스프링 보안 3.x에서 4.x로 마이그레이션 (XML 구성)을 참조하십시오.

    <form name='f'action="login" method='POST'>
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
        <table>
            <tbody>
                <tr>
                    <td>User Name</td>
                    <td><input type="text" name="username" size="30" /></td>
                </tr>
                <tr>
                    <td>Password</td>
                    <td><input type="password" name="password" size="30" /></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="login" /></td>
                </tr>
            </tbody>
        </table>
    </form>
    
  2. ==============================

    2.그것은 defaultSuccessUrl ( "/")입니다.

    그것은 defaultSuccessUrl ( "/")입니다.

       formLogin()
            ...
            .defaultSuccessUrl("/")
       ...
    
  3. ==============================

    3.CORS 문제일까요? 그것이 무엇이든간에 다음을 추가하여 요청과 응답을 확인할 수 있습니다.

    CORS 문제일까요? 그것이 무엇이든간에 다음을 추가하여 요청과 응답을 확인할 수 있습니다.

    authentication-success-handler-ref="appLoginSuccessHandler" 
    authentication-failure-handler-ref="appLoginFailureHandler"
    

    당신의 봄 보안에. 그것은 다음과 같이 보일 것입니다.

    <http use-expressions="true" disable-url-rewriting="true" >
        <logout invalidate-session="true" delete-cookies="true"/>
        <form-login login-page="/YOUR_login_PAGE"
            username-parameter="j_username"
            password-parameter="j_password"
            login-processing-url="/j_spring_security_check"
            authentication-failure-url="/YOUR_login_PAGE"
            default-target-url="/YOUR_login_PAGE" 
            authentication-success-handler-ref="appLoginSuccessHandler" 
            authentication-failure-handler-ref="appLoginFailureHandler"/>
    

    appLoginSuccessHandler 및 appLoginFailureHandler 서비스에서 올바른 메소드를 호출합니다.

    서비스 선언의 예 :

    @Service("appLoginSuccessHandler")
    public class LoginSuccessHandler extends 
    SimpleUrlAuthenticationSuccessHandler{
    
    @Override
    public void onAuthenticationSuccess(
    HttpServletRequest request, HttpServletResponse response, Authentication 
    auth) throws IOException, ServletException{ ......
    .....
    .....
    .....  Here you can handle also CORS ... and more ...
    
  4. ==============================

    4."loginProcessingUrl"도 정확히 지정하십시오.

    "loginProcessingUrl"도 정확히 지정하십시오.

    formLogin()
       ...
       .loginProcessingUrl("/j_spring_security_check")
    ...
    
  5. from https://stackoverflow.com/questions/29554850/spring-security-4-custom-login-j-spring-security-check-return-http-302 by cc-by-sa and MIT license