java - Spring BOOT 安全性:自定义登录页面永远不会进行身份验证
问题描述
我正在开发一个带有 Spring Boot 的 Web 应用程序。我使用过弹簧靴安全性。
如果我使用 spring boot 默认登录页面,身份验证按预期工作
但它不适用于自定义登录页面。
如果我在 websecurity.java 中配置 http 端点时使用自定义登录页面,我将被重定向到登录页面
在下面分享示例代码和我的诊断。
@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";
}
}
登录.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>
UserDetailsService 用于使用 crud Repo 从数据库进行用户身份验证
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;
}
}
解决方案
您需要指定用户名和密码参数的 ID/名称。
默认值为username
and password
,但您使用email
and password
。
您可以更改安全配置中的默认值:
//...
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")
//...
推荐阅读
- protractor - 量角器 - 如何解决获得数字输出的承诺
- php - 带有数据表的外部过滤器表单
- angular7 - 如何在 Ionic 4/Angular7 中以反应形式使用logisticinfotech/ionic4-datepicker?
- sql - BigQuery DATEADD(MAX(myDate), 1, YEAR) 返回函数未找到:DATEADD;你是说 date_add 吗?在 [6:7]
- java - println 的 Junit 测试
- javascript - 更新 Ant Design 后如何修复有关 React.forwardRef() 的警告?
- java - 用 Java 扩展 Kotlin 类需要我重新实现已经实现的方法
- django - django,模型迁移:TypeError:需要一个整数(得到类型str)
- c# - DSA:生成 p
- prometheus - 什么 PromQL 查询给出了任意指标列表的最小当前值?