简体   繁体   English

具有3字段身份验证和自定义登录表单的Spring启动安全性

[英]Spring boot security with 3 fields authentication and custom login form

I'm using spring boot and i need to implement spring security with 3 fields authentication process username, password and corporate identifier as a hidden input in a form. 我正在使用spring boot,我需要使用3字段身份验证过程用户名,密码和公司标识符作为表单中的隐藏输入来实现spring security。

I implemented a custom usernamepasswordauthenticationfilter but it not seems to be enough to setup the security config. 我实现了一个自定义的usernamepasswordauthenticationfilter,但它似乎不足以设置安全配置。

EDIT : 编辑:

Users don't seem to be authenticated ! 用户似乎没有经过身份验证! because a can access to authenticated request defined in web config 因为a可以访问web配置中定义的经过身份验证的请求

EDIT 2 : 编辑2:

in my custom filter when a enter a valid user it's do execute on succesfulAuthentication. 在我的自定义过滤器中,当输入有效用户时,它会在succesfulAuthentication上执行。 What i'm missing please provide me any help :( Here were i am 我缺少什么请给我任何帮助:(我在这里

@Repository
public class AuthenticationUserDetailsService implements UserDetailsService {

private static final Logger LOGGER = Logger.getLogger(AuthenticationUserDetailsService.class);

@Autowired
private UserRepository users;

private org.springframework.security.core.userdetails.User userdetails;

@Override
public UserDetails loadUserByUsername(String input) throws UsernameNotFoundException {
    // TODO Auto-generated method stub

    System.out.println(input);
    String[] split = input.split(":");
    if (split.length < 2) {
        LOGGER.debug("User did not enter both username and corporate domain.");
        throw new UsernameNotFoundException("no corporate identifier is specified");
    }
    String username = split[0];
    String corporateId = split[1];

    System.out.println("Username = " + username);
    System.out.println("Corporate identifier = " + corporateId);

    boolean enabled = true;
    boolean accountNonExpired = true;
    boolean credentialsNonExpired = true;
    boolean accountNonLocked = true;

    com.ubleam.corporate.server.model.User user;

    user = checkUserDetail(username, corporateId);

    if (user == null)
        throw new NotAuthorizedException("Your are not allowed to access to this resource");

    LOGGER.info("User email : " + user.getEmail() + "#User corporate : " + user.getCorporateId());

    userdetails = new User(user.getEmail(), user.getPassword(), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities("ROLE_USER"));
    return userdetails;
}

/**
 * 
 * @param roles
 *            roles granted for user
 * @return List of granted authorities
 * 
 */

public List<GrantedAuthority> getAuthorities(String roles) {

    List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
    authList.add(new SimpleGrantedAuthority(roles));
    return authList;
}

/**
 * User authentication details from database
 * 
 * @param username
 *            to use for authentication
 * @param coporateId
 *            corporate identifier of user
 * @return found user in database
 */
private com.ubleam.corporate.server.model.User checkUserDetail(String username, String corporateId) {

    com.ubleam.corporate.server.model.User user = users.findByEmailAndCorporateId(username, corporateId);

    return user;
}

My custom filter : 我的定制过滤器:

public class PlatformAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

private static final Logger LOGGER = Logger.getLogger(PlatformAuthenticationFilter.class);

private static final String LOGIN_SUCCESS_URL = "{0}/bleamcards/{1}/home";
private static final String LOGIN_ERROR_URL = "{0}/bleamcards/{1}/login?error";
private String parameter = "corporateId";
private String delimiter = ":";
private String corporateId;

@Override
protected String obtainUsername(HttpServletRequest request) {
    String username = request.getParameter(getUsernameParameter());
    String extraInput = request.getParameter(getParameter());

    String combinedUsername = username + getDelimiter() + extraInput;

    setCorporateId(extraInput);
    LOGGER.info("Combined username = " + combinedUsername);
    return combinedUsername;
}

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException, ServletException {

    String contextPath = request.getContextPath();
    String url = MessageFormat.format(LOGIN_SUCCESS_URL, contextPath, corporateId);

    response.sendRedirect(url);
}

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {

    String contextPath = request.getContextPath();
    String url = MessageFormat.format(LOGIN_ERROR_URL, contextPath, corporateId);

    response.sendRedirect(url);
}

public String getParameter() {
    return parameter;
}

public void setParameter(String corporateId) {
    this.parameter = corporateId;
}

public String getDelimiter() {
    return delimiter;
}

public void setDelimiter(String delimiter) {
    this.delimiter = delimiter;
}

public String getCorporateId() {
    return corporateId;
}

public void setCorporateId(String corporateId) {
    this.corporateId = corporateId;
}
}

And finally the web security config : 最后是web安全配置:

@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Inject
private AuthenticationManagerBuilder auth;
@Inject
private UserDetailsService userDS;

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.authorizeRequests().antMatchers("/bleamcards/**/login", "/bleamcards/**/forgetpassword", "/bleamcards/**/register", "/css/**", "/js/**", "/images/**", "/webjars/**")
            .permitAll().anyRequest().authenticated().and().addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class).formLogin().loginPage("/login")
            .defaultSuccessUrl("/").permitAll().and().logout().permitAll();
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.eraseCredentials(false);
    auth.userDetailsService(userDS).passwordEncoder(new BCryptPasswordEncoder());

}

@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
    return auth.build();
}

@Bean
public PlatformAuthenticationFilter authenticationFilter() throws Exception {
    PlatformAuthenticationFilter authFilter = new PlatformAuthenticationFilter();
    authFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
    authFilter.setAuthenticationManager(authenticationManager());
    authFilter.setUsernameParameter("username");
    authFilter.setPasswordParameter("password");
    authFilter.setParameter("corporateId");
    return authFilter;
}

@Override
protected UserDetailsService userDetailsService() {
    return userDS;
}

I want users to be able to connect only to /login /register /forgetpasswod urls for their respective corporate platforms 我希望用户只能连接到各自公司平台的/ login / register / forgetpasswod网址

Actually i manage to find a solution to my issue. 实际上我设法找到解决我的问题的方法。

I added successHandler on successfulAuthentication was missing ! 我在successAuthentication上添加了successHandler失踪! And a failureHandler too on unsuccessfulAuthentication methods. 并且对于不成功的身份验证方法也是一个失败的手柄。

Here is my new Authentication filter : 这是我的新身份验证过滤器:

public class TwoFactorAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

private static final String LOGIN_SUCCESS_URL = "{0}/bleamcards/{1}/home"; 
private static final String LOGIN_ERROR_URL = "{0}/bleamcards/{1}/login?error";
private String parameter = "corporateId";
private String delimiter = ":";
private String corporateId;


@Override
protected String obtainUsername(HttpServletRequest request) {
    String username = request.getParameter(getUsernameParameter());
    String extraInput = request.getParameter(getParameter());
    String combinedUsername = username + getDelimiter() + extraInput;

    setCorporateId(extraInput);
    System.out.println("Combined username = " + combinedUsername);
    return combinedUsername;
}

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain , Authentication authResult) throws IOException, ServletException {

    String contextPath = request.getContextPath();
    String url = MessageFormat.format(LOGIN_SUCCESS_URL, contextPath, corporateId);
    setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler(url));
    super.successfulAuthentication(request, response, chain, authResult);

}

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {

    String contextPath = request.getContextPath();
    String url = MessageFormat.format(LOGIN_ERROR_URL, contextPath, corporateId);
    setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(url));

    super.unsuccessfulAuthentication(request, response, failed);
}

public String getParameter() {
    return parameter;
}

public void setParameter(String corporateId) {
    this.parameter = corporateId;
}

public String getDelimiter() {
    return delimiter;
}

public void setDelimiter(String delimiter) {
    this.delimiter = delimiter;
}

public String getCorporateId() {
    return corporateId;
}

public void setCorporateId(String corporateId) {
    this.corporateId = corporateId;
}
}

Did you check that your AuthenticationUserDetailsService code is actually been executed? 您是否检查过您的AuthenticationUserDetailsService代码是否已被执行? If the framework is not invoking it this means that your configuration is not properly hooking that UserDetailsService . 如果框架没有调用它,这意味着您的配置没有正确挂钩UserDetailsService In your WebSecurityConfig I think you need to have this: 在你的WebSecurityConfig我认为你需要这样:

@Bean
public AuthenticationManager getAuthenticationManager() throws Exception {
    return super.authenticationManagerBean(); //not return auth.build();
}

I suggest you to take a look at this branch from Stormpath . 我建议你看看Stormpath的 这个分店。 There, they are configuring Spring Boot to use a custom AuthenticationProvider (similar to an UserDetailsService ). 在那里,他们正在配置Spring Boot以使用自定义AuthenticationProvider (类似于UserDetailsService )。 That module uses and depends on this other Spring Security module . 该模块使用并依赖于其他Spring Security模块

Then, this sample Spring Security Example (note that it is not Spring Boot, but just Spring) will give you a complete example of the way the Spring Security Java Config is done. 然后, 这个示例Spring安全示例 (请注意它不是Spring Boot,而只是Spring)将为您提供Spring Security Java Config完成方式的完整示例。 Please note that this Java Config extends this one which actually hides much of the actual internal configuration. 请注意,此Java Config扩展了这个实际隐藏了大部分实际内部配置的Java Config。

Disclaimer, I am an active Stormpath contributor. 免责声明,我是Stormpath的积极贡献者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM