Java Spring引导安全性:自定义登录页从不进行身份验证
我正在用spring boot开发一个web应用程序。我使用了spring boot安全性 如果使用spring boot默认登录页面,身份验证将按预期工作 但它不适用于自定义登录页面 如果在websecurity.java中配置http端点时使用自定义登录页面,我将被重定向到登录页面 下面分享示例代码和我的诊断Java Spring引导安全性:自定义登录页从不进行身份验证,java,spring,spring-boot,spring-security,Java,Spring,Spring Boot,Spring Security,我正在用spring boot开发一个web应用程序。我使用了spring boot安全性 如果使用spring boot默认登录页面,身份验证将按预期工作 但它不适用于自定义登录页面 如果在websecurity.java中配置http端点时使用自定义登录页面,我将被重定向到登录页面 下面分享示例代码和我的诊断 @EnableGlobalMethodSecurity(prePostEnabled = true) @EnableWebSecurity @EnableJpaRepositories
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@EnableJpaRepositories(basePackageClasses = UserRepository.class)
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService userDetailsService;
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and().formLogin().loginPage("/loginPage")
.permitAll();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(getPasswordEncoder());
}
private PasswordEncoder getPasswordEncoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return true;
}
};
}
}
控制器:
@Controller
@EnableAutoConfiguration
@ComponentScan("com.shopping.service")
public class ShoppingController {
@Autowired
private ShoppingService service;
@RequestMapping("/")
public String index() {
return "";
}
@RequestMapping("/loginPage")
public String welcome(Map<String, Object> model) {
return "login";
}
@RequestMapping(value = "/register")
public String register(Model model) {
model.addAttribute("user", new User());
return "register";
}
@RequestMapping(value = "/submitRegistration", method = RequestMethod.POST)
public String submitRegistration(@ModelAttribute User user) {
User saved = service.save(user);
System.out.println(saved);
return "login";
}
@RequestMapping("/home")
public String home() {
return "home";
}
}
@控制器
@启用自动配置
@组件扫描(“com.shopping.service”)
公共类购物控制器{
@自动连线
私人购物服务;
@请求映射(“/”)
公共字符串索引(){
返回“”;
}
@请求映射(“/loginPage”)
公共字符串欢迎(地图模型){
返回“登录”;
}
@请求映射(value=“/register”)
公共字符串寄存器(模型){
model.addAttribute(“user”,new user());
返回“登记簿”;
}
@RequestMapping(value=“/submitRegistration”,method=RequestMethod.POST)
公共字符串提交注册(@modeldattribute User){
用户保存=服务。保存(用户);
系统输出打印项次(已保存);
返回“登录”;
}
@请求映射(“/home”)
公共字符串home(){
返回“家”;
}
}
login.html:
<form th:action="@{/loginPage}" method="post" th:object="${object}">
<div class="form-group">
<label for="username">Email address:</label>
<input type="email" name="username" class="form-control" id="username">
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="password" name="password" class="form-control" id="password">
</div>
<div class="checkbox">
<label><input type="checkbox"> Remember me</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
<a href="/register" class="btn btn-default">Register</a>
</form>
电邮地址:
密码:
记得我吗
提交
用于使用crud Repo从数据库进行用户身份验证的UserDetails服务
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepo;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
Optional<User> optionalUser = userRepo.findByEmail(userName);
optionalUser.orElseThrow(() -> new UsernameNotFoundException("User Name not found"));
UserDetailsImpl userDetails = optionalUser.map(user -> new UserDetailsImpl(user)).get();
return userDetails;
}
}
public class UserDetailsImpl extends User implements UserDetails {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
public UserDetailsImpl(User user) {
this.setEmail(user.getEmail());
this.setAge(user.getAge());
this.setName(user.getName());
this.setId(user.getId());
this.setPassword(user.getPassword());
}
@Override
public String getPassword() {
return super.getPassword();
}
@Override
public String getUsername() {
return super.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
公共类CustomUserDetailsService实现UserDetailsService{
@自动连线
私有用户存储库userRepo;
@凌驾
public UserDetails loadUserByUsername(字符串用户名)引发UsernameNotFoundException{
可选optionalUser=userRepo.findByEmail(用户名);
optionalUser.OrelsThrow(()->new UsernameNotFoundException(“未找到用户名”);
userdetailsiml userDetails=optionalUser.map(user->newuserdetailsiml(user)).get();
返回用户详细信息;
}
}
公共类UserDetailsImpl扩展用户实现UserDetails{
@凌驾
public Collection您需要指定用户名和密码参数的ID/名称
默认值为用户名
和密码
,但您使用电子邮件
和密码
您可以在安全配置中更改默认设置:
//...
and().formLogin()
.loginPage("/loginPage")
.usernameParameter("email").passwordParameter("password")
//...
请注意,您只需要更改一个与默认值不同的方法,我只想显示这两种方法
编辑1
第二个错误是表单操作,它必须是由loginPage(“/loginPage”)
方法指定的,因此在本例中:th:action=“@{/loginPage}”
此外,密码标签的for属性错误(在这种情况下必须是password
)
我测试了这个,现在它对我有效了
编辑2
Spring security的工作方式与您想象的不一样。它会截取表单的操作URL,并将您重定向到登录前尝试访问的页面。如果您想更改此设置,可以使用successForwardUrl()
在您的示例中:
//...
and().formLogin()
.loginPage("/loginPage")
.successForwardUrl("/home")
//...
即使在添加usernameParameter(“电子邮件”)之后,我不知怎的看到响应被重定向到登录页面。即使将电子邮件字段的名称和id更改为用户名也不起作用。你能更新你的问题吗?你清理并重建了你的应用程序吗?此外,你应该将@Bean
注释添加到你的getPasswordEncoder
方法中。如果我不要使用自定义登录页,使用spring默认登录页,这样getPasswordEncoder就不会导致issueYeah,但它不是一个bean,因此不是由spring管理的,以后可能会导致其他问题。面对同样的问题,它在添加.csrf().disable()后开始工作