与 mongodb 后端数据库的基于 Spring Security 的身份验证混淆
Posted
技术标签:
【中文标题】与 mongodb 后端数据库的基于 Spring Security 的身份验证混淆【英文标题】:Confusion with Spring Security-based authentication with mongo backed db 【发布时间】:2016-12-12 18:21:39 【问题描述】:我正在尝试将用户登录到一个网页,其中凭据存储在 mongodb 中。 我正在使用 spring boot,但不知道 spring 安全功能。
这就是我最终使用以下控制器代码的原因:
@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);
用户认证服务:
@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 - 型号:
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>
时,它仍然会将我重定向到登录表单。
我还在UserAuthenticationService
中放置了一些log.debug(..)
,但我根本看不到它们中的任何一个..
在大多数其他示例中,我什至看不到映射到 \login
的基本控制器方法,但我认为这是因为 spring 在幕后做了这 4 个我?!
请注意,我没有使用任何权限和/或角色,因为它还没有在 db 中建模。在使用 Spring Security 时,这是必须具备的吗,因为大多数示例都包括角色和权限。
编辑:(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>
更新:(我在上面提到的代码上试过的东西):
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) 将 @Override 替换为 @Autowired 注释(从另一个 SO 帖子中获得 - 不起作用):
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(daoAuthenticationProvider());
【问题讨论】:
您在哪里指定了您的受限 URL? 不是在configure(HttpSecurity http)
:...anyRequest().authenticated()
完成的
【参考方案1】:
我可以解决这个..
阅读this blog post 事实证明,这是需要的!在config(HttpSecurity http)
中指定usernameParameter(..), passwordParameter(..)
,这与它们在许多基本示例或教程中所做的不同。所以依赖默认值是我的遗憾。我必须附加:
formLogin().loginPage("/")
.loginProcessingUrl("/login")
.failureUrl("/")
.defaultSuccessUrl("/main")
.usernameParameter("username") //needed, if custom login page
.passwordParameter("password") //needed, if custom login page
没有这些参数设置,UserDetailsService
实现不会被触发。
希望对大家有所帮助。
【讨论】:
【参考方案2】:将您的 SessionCreationPolicy
更改为 IF_REQUIRED
或 ALWAYS
。目前,它是“无状态的”,这意味着您的会话将永远不会为 SecurityContext
创建或获取。
【讨论】:
我试过了,但还是不行。还尝试从配置中完全删除sessionManagement()
,但结果相同以上是关于与 mongodb 后端数据库的基于 Spring Security 的身份验证混淆的主要内容,如果未能解决你的问题,请参考以下文章
基于 Spring Cloud 微服务与 Zuul 的 Spring CORS 过滤器问题
Java开发学习视频!基于java的个人博客系统的设计与实现