2016-08-18 28 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