小编典典

Spring Security-在REST服务中将凭证作为JSON而不是常规格式发送

json

我正在rest与一起写服务json。对于后端,我使用Spring Security。我有形式巫婆发送与ajax rest对象,如下所示:

{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;
    }

}

但是不幸的是,这个过滤器似乎不起作用。

当我从登录表单发送ajax发布请求时,我得到了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)一样,然后将其重定向到login?error不存在的原因,因为我有自己的登录表单。

请帮忙。


编辑

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 {
}

阅读 316

收藏
2020-07-27

共1个答案

小编典典

好吧,除非您编写 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());

}

PD Yo必须使用Post,否则您将永远无法使用GET发布请求正文

2020-07-27