2016-08-18 30 views
0

我正在开发一个RESTful Web服务并已登录工作。我想补充的安全和访问令牌,所以我说一个UserDetailsService,如下图所示:弹簧安全loadByUsername的用户名字段为空

@Component 
public class CustomLoginAuthenticationProvider implements UserDetailsService { 

    @Autowired 
    private BusinessUserService businessUserService; 

    @Override 
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { 
     if(email == null || email.isEmpty() || !email.contains("@")) { 
      System.out.println("ERROR - THIS IS THE USERNAME:" + email); 
      throw new UsernameNotFoundException(email); 
     } 
    //... More below, but it doesn't matter. Exception thrown every time 
} 

然而,电子邮件字符串是空的。我不明白为什么,因为我很难明确何时调用此方法以及发送什么值作为此方法的参数,因为这是发送JSON的REST后端。这是我的WebSecurityConfigurerAdapter设置:

@Configuration 
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER) 
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { 

    @Bean 
    public CustomLoginAuthenticationProvider customLoginAuthenticationProvider() { 
     return new CustomLoginAuthenticationProvider(); 
    } 

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

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .authorizeRequests() 
      .antMatchers("/css/**", "/js/**", "/images/**", "/fonts/**", 
         "/videos/**", "/", "/register", "/login", "/about", 
         "/contact", "/test") 
      .permitAll() 
     .and() 
      .authorizeRequests() 
      .anyRequest() 
      .authenticated()        
     .and() 
      .exceptionHandling() 
      .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")) 
     .and() 
      .formLogin() 
      .loginPage("/login") 
      .loginProcessingUrl("/login") 
      .usernameParameter("email") 
      .passwordParameter("password") 
     .and() 
      .logout() 
      .logoutSuccessUrl("/") 
      .permitAll() 
     .and() 
      .csrf() 
      .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) 
     .and() 
      .addFilterAfter(new CsrfTokenFilter(), CsrfFilter.class); 
    } 
} 

我指定的电子邮件应该当我使用.usernameParameter("email"),所以我真的不知道为什么它不填充email参数发送至方法。我在前端使用AngularJS,并使用JSON将凭证发送到后端。

+0

你可以把你的登录表单吗? –

回答

1

如果您使用json发送凭证,则此处的错误是由于电子邮件不是http参数,因此被包含在RequestBody中。

默认UsernamePasswordAuthenticationFilter需要的凭据从http PARAM:

public class UsernamePasswordAuthenticationFilter extends 
     AbstractAuthenticationProcessingFilter { 


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

      String username = obtainUsername(request); 
      String password = obtainPassword(request); 
      ... 
    } 

    /** 
     * Enables subclasses to override the composition of the password, such as by 
     * including additional values and a separator. 
     * <p> 
     * This might be used for example if a postcode/zipcode was required in addition to 
     * the password. A delimiter such as a pipe (|) should be used to separate the 
     * password and extended value(s). The <code>AuthenticationDao</code> will need to 
     * generate the expected password in a corresponding manner. 
     * </p> 
     * 
     * @param request so that request attributes can be retrieved 
     * 
     * @return the password that will be presented in the <code>Authentication</code> 
     * request token to the <code>AuthenticationManager</code> 
     */ 
     protected String obtainPassword(HttpServletRequest request) { 
      return request.getParameter(passwordParameter); 
     } 

     /** 
     * Enables subclasses to override the composition of the username, such as by 
     * including additional values and a separator. 
     * 
     * @param request so that request attributes can be retrieved 
     * 
     * @return the username that will be presented in the <code>Authentication</code> 
     * request token to the <code>AuthenticationManager</code> 
     */ 
     protected String obtainUsername(HttpServletRequest request) { 
      return request.getParameter(usernameParameter); 
     } 

你必须写下自己的过滤器,你必须阅读从RequestBody传入的凭据,并在UsernamePasswordAuthenticationFilter的位置设置在您的配置。

你可以看看https://stackoverflow.com/a/35724932/4190848https://stackoverflow.com/a/35699200/4190848

0

另一种解决方案,那是很容易的,就是做这在您的客户端应用程序 - 工作正常使用Spring Security:

public login(username: string, password: string) { 
    const headers = new Headers(); 
    headers.append('Content-Type', 'application/x-www-form-urlencoded'); 

    return this.http.post(
     `http://www.myserver.com:8080/myApp/login`, 
     encodeURI(`username=${username}&password=${password}`), 
     { headers } 
    ); 
    } 
} 

这个隐藏来自url的参数并将它们编码为表单数据,而spring security的默认实现非常喜欢这个。

+0

确保您将它们作为参数传递,而不是JSON数据。 传递JSON数据作为参数的角方式 $ HTTP({ \t \t 'URL': '注册', \t \t '方法': 'POST', \t \t 'PARAMS':用户 \t} ) – Ram