java - Spring security-在 rest 服务中将凭据作为 json 而不是常规形式发送

标签 java json spring web-services rest

我正在使用 json 编写 rest 服务。对于后端,我使用 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();
    }
}

问题是 spring 安全要求我将凭据作为正文发送,但我想 spring 接受我的 Json 对象。

所以我基于 this 编写了自己的身份验证过滤器:

@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 post 请求时,我得到 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 {
}

最佳答案

嗯,在您编写 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你必须使用 Post,你将永远无法使用 GET 发布请求正文

关于java - Spring security-在 rest 服务中将凭据作为 json 而不是常规形式发送,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35724278/

相关文章:

sql - 从具有带键值对的 json 对象的列中查找最大值

java - Spring Remoting 序列化和反序列化

java - 黑客对 jar 文件进行校对

java - 在tomcat 6上部署spring应用程序时出现异常

ios - 如何通过 Post 方法使用 JSON 模型将 JSON 字典作为参数传递?

json - 如何从 node_modules 文件夹添加 package.json 依赖项?

java - 提交表单时收到错误消息 : "The request sent by the client was syntactically incorrect"

java - 将 spring bean 加载到 servlet

java - 如何对需要时间执行操作的线程进行单元测试

java - 通过 webhook 发送 FulfillmentMessage 和 FollowupEventInput