使用mongo支持的数据库与基于Spring Security的身份验证混淆

时间:2016-08-06 12:40:33

标签: java spring mongodb spring-security spring-boot

我试图将用户登录到网页,其中凭据存储在mongodb中。 我使用弹簧靴并且不知道弹簧安全功能。

这就是我最终使用以下控制器代码结束的原因。

@RequestMapping("/auth")
String auth(@ModelAttribute("credential") Credential credential) throws AuthenticationFailedException {
    handler.authenticateUser(credential);
    log.debug("user: " + credential.getUsername() + " authenticated successfully via /auth");
    return "main";
}

处理程序:

@Autowired
private UserRepository repository;

public boolean authenticateUser(Credential credential) throws AuthenticationFailedException {        
    User authenticatedUser = repository.findByCredentialUsername(credential.getUsername());

    if (authenticatedUser == null)
        throw new AuthenticationFailedException(
                "cant find any user with name: " + credential.getUsername());

    boolean matches = EncryptionUtils.matchEncryptedPassword(credential.getPassword(),
            authenticatedUser);

    if (!matches)
        throw new AuthenticationFailedException(
                "provided password is not matching password stored in database");

    return matches;
}

在意识到使用spring-security相对容易设置servlet过滤器等之后,我改变了我的代码,所以我最终得到了这个......

配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  UserAuthenticationService userAuthService;

  @Bean
  public DaoAuthenticationProvider daoAuthenticationProvider() {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(userAuthService);
    provider.setPasswordEncoder(new BCryptPasswordEncoder());
    return provider;
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.userDetailsService(userAuthService).authorizeRequests()
            .antMatchers("/register", "/", "/css/**", "/images/**", "/js/**", "/login")
            .permitAll().anyRequest().authenticated().and().
            formLogin().loginPage("/").and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable();

  }

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(daoAuthenticationProvider());
  }

SecurityWebInit:

public class SecurityWebInit extends AbstractSecurityWebApplicationInitializer {
  public SecurityWebInit() {
    super(SecurityConfig.class);
  }
}

UserAuthenticationService:

@Component
public class UserAuthenticationService implements UserDetailsService {
  private static final Logger log = Logger.getLogger(UserAuthenticationService.class);
  @Autowired
  private UserRepository repository;

  @Override
  public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = repository.findByCredentialUsername(username);
        log.debug("called user auth service..");
        if (user == null)
            throw new UsernameNotFoundException("username :"+username+" not found.");
        else {
            AuthenticatedUser authUser = new AuthenticatedUser(user);
            return authUser;
        }
  }
}

AuthenticatedUser - model:

public class AuthenticatedUser implements UserDetails {  
  private User user; // user is my own model, not of spring-framework
  private static final Logger log = Logger.getLogger(AuthenticatedUser.class);

  public AuthenticatedUser(User user) {
      this.user = user;
  }
  .. //rest of interface impl. (any method returns true)

  //no roles or authorities modeled, yet
  @Override 
  public Collection<? extends GrantedAuthority> getAuthorities() {
      return null;
  }

修改后的控制器:

@RequestMapping(method=RequestMethod.POST, value="/login")
String auth2(@RequestParam("username") String username, @RequestParam("password") String password) throws AuthenticationFailedException {
    Credential cred = new Credential();
    cred.setUsername(username);
    cred.setPassword(password);        
    handler.authenticateUser(cred);
    log.debug("user: " + cred.getUsername() + " authenticated successfully via /login");
    return "main";
}

模板:

<form method="post" action="/login" th:object="${credential}">
    <div class="form-group">
     <input type="email" th:field="*{username}" class="form-control"
      id="username" placeholder="Username/Email" />
    </div>
    <div class="form-group">
     <input type="password" th:field="*{password}"
      class="form-control" id="password" placeholder="Password" />
    </div>
    <button type="submit" class="btn btn-default login-button">Submit</button>
</form>

所有提供的代码,从另一个教程和示例中更少集中在一起。 当我通过基于表单的登录进行身份验证时,它确实有效。但是在我登录后,当我导航到localhost:8080/<anyRestrictedUrl>时,它仍然会将我重定向到登录表单。 我还在log.debug(..)内放置了一些UserAuthenticationService,但我根本看不到它们中的任何一个...... 在大多数其他示例中,我甚至无法看到映射到\login的基本控制器方法,但我认为这是因为Spring在幕后做了这个4我!

请注意,我没有使用任何权限和/或角色,因为这不是在db中建模的。在使用Spring安全性时,这是必须的,因为大多数示例包括角色和权限。

@edit(pom.xml的相关部分):

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.3.3.RELEASE</version>
    <relativePath />
</parent>

 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
 </dependency>
 <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
 </dependency>
 <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-crypto</artifactId>
 </dependency>
 <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-core</artifactId>
 </dependency>
 <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-config</artifactId>
 </dependency>
 <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-web</artifactId>
 </dependency>
 <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-taglibs</artifactId>
 </dependency>

@update(我在上面提到的代码上试过的东西):

1)设置其他会话策略:(不工作)

 http.userDetailsService(userAuthService).authorizeRequests()
            .antMatchers("/register", "/", "/css/**", "/images/**", "/js/**", "/login")
            .permitAll().anyRequest().authenticated().and().
            formLogin().loginPage("/").and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS).and().csrf().disable();

2)用@Autowired注释取代@Override(从另一个SO帖子中获取 - 不工作):

 @Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(daoAuthenticationProvider());
}

2 个答案:

答案 0 :(得分:2)

我可以解决这个问题.. 随着this blog post的阅读,结果证明它需要!在usernameParameter(..), passwordParameter(..)中指定config(HttpSecurity http),与许多基本示例或教程中的formLogin().loginPage("/") .loginProcessingUrl("/login") .failureUrl("/") .defaultSuccessUrl("/main") .usernameParameter("username") //needed, if custom login page .passwordParameter("password") //needed, if custom login page 不同。所以依靠默认值是我的遗憾。我不得不追加:

UserDetailsService

如果没有这些参数设置,<div class="row portfolio-examples"> <?php if( have_rows('portfolio_examples') ): while ( have_rows('portfolio_examples') ) : the_row(); $count = 0; $work = get_sub_field('portfolio_work'); ?> <?php if ($count != 0 || $count < 4) :?> <div class="large-6 medium-6 columns end"> <?php if( $work ): ?> <img src="<?php echo $work['url']; ?>" alt="<?php echo $work['alt'] ?>" /> <?php endif; ?> </div> <?php else: ?> <div class="large-8 medium-8 large-centered medium-centered columns"> <?php if( $work ): ?> <img src="<?php echo $work['url']; ?>" alt="<?php echo $work['alt'] ?>" /> <?php endif; ?> </div> <?php endif; ?> <?php $counter++; endwhile; endif; ?> </div>实现就不会被触发。

希望它可以帮助任何人。

答案 1 :(得分:0)

将您的SessionCreationPolicy更改为IF_REQUIREDALWAYS。目前,它是“无国籍”,这意味着永远不会为SecurityContext创建或获取您的会话。