복붙노트

[SPRING] 봄 보안 - 휴식 서비스에서 일반 양식 대신 json으로 자격 증명을 전송합니다.

SPRING

봄 보안 - 휴식 서비스에서 일반 양식 대신 json으로 자격 증명을 전송합니다.

나는 json과 휴식 서비스를 쓰고있다. 백엔드에서는 Spring Security를 ​​사용합니다. 나는 양식 마녀가 다음과 같이 아약스 휴식 개체와 함께 보낸다 :

{email: "admin", password: "secret"}

이제 서버에서 다음과 같이 구성합니다.

@Configuration
@EnableWebSecurity
@ComponentScan("pl.korbeldaniel.cms.server")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
    @Autowired
    private RestAuthenticationSuccessHandler authenticationSuccessHandler;
    @Autowired
    private RestAuthenticationFailureHandler authenticationFailureHandler;

    @Bean
    JsonAuthenticationFilter jsonAuthenticationFilter() throws Exception {
    JsonAuthenticationFilter filter = new JsonAuthenticationFilter();
    filter.setAuthenticationManager(authenticationManagerBean());
    System.out.println("jsonAuthenticationFilter");
    return filter;
    }

    @Bean
    public RestAuthenticationSuccessHandler mySuccessHandler() {
    return new RestAuthenticationSuccessHandler();
    }

    @Override
    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser("admin").password("secret").roles("ADMIN");
    // auth.jdbcAuthentication().
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(jsonAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    http.csrf().disable();//
    http.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint)//
        .and().authorizeRequests()//
        .antMatchers("/").permitAll()//
        .antMatchers("/services/anonymous/**").permitAll()//
        .antMatchers("/services/authenticated/**").authenticated()//
        .and().formLogin().loginProcessingUrl("/services/anonymous/loginService/login").usernameParameter("email").passwordParameter("password")//
        .successHandler(authenticationSuccessHandler)//
        .and().logout().logoutUrl("/services/anonymous/loginService/logout");
    // http.httpBasic();
    }
}

문제는 스프링 보안이 나에게 시체로 자격증을 요구한다는 것이지만, 나는 나의 Json 객체를 받아 들일 만하다.

그래서 나는 이것에 대한 나의 자신의 인증 필터베이스를 썼다 :

@Component
public class JsonAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private boolean postOnly;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    System.out.println("attemptAuthentication");
    if (postOnly && !request.getMethod().equals("POST")) {
        throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    }

    UsernamePasswordAuthenticationToken authRequest = this.getUserNamePasswordAuthenticationToken(request);

    // Allow subclasses to set the "details" property
    setDetails(request, authRequest);

    return this.getAuthenticationManager().authenticate(authRequest);
    }

    /**
     * @param request
     * @return
     */
    private UsernamePasswordAuthenticationToken getUserNamePasswordAuthenticationToken(HttpServletRequest request) {
    // TODO Auto-generated method stub
    System.out.println(request);
    return null;
    }

}

하지만 불행히도이 필터는 작동하지 않는 것 같습니다.

로그인 폼에서 아약스 게시물 요청을 보내면 302 Found를 얻었고 다음으로 이것을 얻습니다.

Remote Address:127.0.0.1:8080
Request URL:http://localhost:8080/cms/login?error
Request Method:GET
Status Code:404 Not Found

마찬가지로 사용자 자격 증명을 확인하지 못했습니다 (원인은 양식 본문이 비어 있고 자격 증명이 json으로 변경됨). 그런 다음 로그인으로 리디렉션됩니까? 내 로그인 양식이 있기 때문에 존재하지 않는 오류입니다.

도와주세요.

편집하다

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

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

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


@EnableWebMvc
@ComponentScan(basePackages = "pl.daniel.cms.server")
public class WebConfig extends WebMvcConfigurerAdapter {
}

해결법

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

    1.getUserNamePasswordAuthenticationToken 본문을 작성하기 전까지는 작동하지 않아야합니다.

    getUserNamePasswordAuthenticationToken 본문을 작성하기 전까지는 작동하지 않아야합니다.

    실제로, 당신은 HttpServletRequest의 요청 본문을 읽고 Jackson 또는 다른 매핑 방법을 통해 구문 분석 한 다음 UsernamePasswordAuthenticationToken을 만들어야합니다.

    Jackson을 사용하여 (Spring 버전에 따라 올바른 버전을 선택하십시오), 다음과 같은 간단한 bean을 생성 할 것입니다 :

    @JsonIgnoreProperties(ignoreUnkown=true)
        public LoginRequest{
         private String email;
         private String password;
         // getters & setters
        }
    

    요청 본문을 매핑하는 데 사용합니다.

    private UsernamePasswordAuthenticationToken getUserNamePasswordAuthenticationToken(HttpServletRequest request)  throws IOException{
        StringBuffer sb = new StringBuffer();
        BufferedReader bufferedReader = null;
        String content = "";
        LoginRequest sr = null;
    
        try {
            bufferedReader =  request.getReader()
            char[] charBuffer = new char[128];
            int bytesRead;
            while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 ) {
                sb.append(charBuffer, 0, bytesRead);
            }
            content = sb.toString();
            ObjectMapper objectMapper = new ObjectMapper();
            try{
                sr = objectMapper.readValue(content, LoginRequest.class);
            }catch(Throwable t){
                throw new IOException(t.getMessage(), t);
            }
        } catch (IOException ex) {
    
            throw ex;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        return new UsernamePasswordAuthenticationToken(sr.getEmail(), sr.getPassword());
    

    }

    P.D. Yo는 Post를 사용해야합니다. GET을 사용하여 요청 본문을 게시 할 수 없습니다.

  2. from https://stackoverflow.com/questions/35724278/spring-security-send-credentials-as-json-instead-of-regular-form-in-rest-servic by cc-by-sa and MIT license