java - spring boot 安全配置不正确
问题描述
我是新手Spring boot
和Spring boot security
。但是,使用现有的示例代码,我编写了一个可以正常工作的代码。在我的设计中,我有一个单独的登录页面,名为login.html
. 现在,我改变了我的设计,我的登录和注册form
在主页上是一个单一的,这似乎是有问题的。在这里,我更详细地解释了这个问题:
- 我打开主页,然后单击登录按钮。2)我输入用户名和密码,然后单击登录按钮。然后,我看到了
dashboard
预期的页面。到现在为止还挺好。
主页如下所示:
这是登录/注册表单的代码home.html
:
<form th:action="@{/signup}" method="post">
<input type="hidden" name="action" id="action" value="">
<div>
<input type="email" name="email" id="inputEmail" placeholder="email" required>
</div>
<div>
<input type="password" name="password" id="inputPassword" placeholder="password" required>
</div>
<button type="submit">SIGN IN</button>
</form>
这是signin/signup
控制器:
@RequestMapping(value = "/signup", method = RequestMethod.POST)
public ModelAndView createNewUser(@Valid User user, BindingResult bindingResult, @RequestParam("action") String action) {
String act = action;
ModelAndView modelAndView = new ModelAndView();
User userExists = userService.findUserByEmail(user.getEmail());
if(action.equalsIgnoreCase("signup")) {
if (userExists != null) {
bindingResult
.rejectValue("email", "error.user",
"There is already a user registered with the username");
}
if (bindingResult.hasErrors()) {
modelAndView.setViewName("signup");
} else {
userService.saveUser(user);
modelAndView.addObject("successMessage", "User has been registered successfully");
modelAndView.addObject("user", new User());
modelAndView.setViewName("home");
}
}else if(action.equalsIgnoreCase("signin")) {
modelAndView.addObject("currentUser", userExists);
modelAndView.addObject("firstname", userExists.getFirstname());
modelAndView.addObject("lastname", userExists.getLastname());
modelAndView.addObject("adminMessage", "Content Available Only for Users with Admin Role");
modelAndView.setViewName("dashboard");
}
return modelAndView;
}
到目前为止,一切正常,登录后,我被转发到如下所示的dashboard
页面:
现在,如果我单击John
哪个应该将我转发到个人资料页面或单击submit
哪个应该将我转发到另一个页面,它返回到用户未登录的主页。这是仪表板中的表单,当我单击submit
按钮时应该调用控制器方法:
<form action="/addReview" method="POST" name="addReviewForm"onsubmit="return validateForm()">
<input type="hidden" id="category"name="category" />
<input type="text" id="first_input" name="first_point" placeholder="Point 1">
<input type="text" id="seventh_input" name="seventh_point" placeholder="Point 7">
<button type="submit">submit</button></form>
这是安全性的配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
// .antMatchers("/login").permitAll()
.antMatchers("/signup").permitAll()
.antMatchers("/search").permitAll()
.antMatchers("/dashboard/**").hasAuthority("ADMIN").anyRequest()
.authenticated().and().csrf().disable().formLogin().successHandler(customizeAuthenticationSuccessHandler)
.loginPage("/").failureUrl("/?error=true")
.usernameParameter("email")
.passwordParameter("password")
.and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and().exceptionHandling();
}
我认为问题在于.loginPage("/").failureUrl("/?error=true")
,但我不确定。我没有任何单独的登录页面。同时,该函数validateForm()
被正确调用。只是没有调用控制器方法。
我希望有人能帮助我。
提前致谢,
##更新 1: ##
我更改并简化了代码,以便更容易找到问题。现在,我的表格中有以下表格home.html
:
<form th:action="@{/}" method="post">
<input type="email" name="email" id="inputEmail" placeholder="email" required>
<input type="password" name="password" id="inputPassword" placeholder="password" required>
<input type="submit" value="SIGN IN" />
以及以下配置:
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/search").permitAll()
.antMatchers("/dashboard/**").hasAuthority("ADMIN").anyRequest()
.authenticated()
.and().csrf().disable().formLogin().successHandler(customizeAuthenticationSuccessHandler)
.loginPage("/")
.failureUrl("/?error=true")
.usernameParameter("email")
.passwordParameter("password").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and().exceptionHandling();
}
以及以下控制器:
@RequestMapping(value = "/", method = RequestMethod.POST)
public ModelAndView createNewUser(@Valid User user, BindingResult bindingResult, @RequestParam("email") String email) {
ModelAndView modelAndView = new ModelAndView();
User userExists = userService.findUserByEmail(user.getEmail());
modelAndView.addObject("currentUser", userExists);
modelAndView.addObject("firstname", userExists.getFirstname());
modelAndView.addObject("lastname", userExists.getLastname());
modelAndView.setViewName("dashboard");
return modelAndView;
}
@RequestMapping(value = {"/","/home"}, method = RequestMethod.GET)
public ModelAndView home() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("home");
return modelAndView;
}
使用此代码,我什至看不到仪表板。单击sign in
按钮将我返回到该http://localhost:8080/?error=true
页面。
解决方案
从安全配置开始,我将使用 lambda DSL 重写它并解释它在做什么。
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorize -> authorize
.antMatchers("/").permitAll()
.antMatchers("/signup").permitAll()
.antMatchers("/search").permitAll()
.antMatchers("/dashboard/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
)
.formLogin(formLogin -> formLogin
.successHandler(customizeAuthenticationSuccessHandler)
.loginPage("/")
.failureUrl("/?error=true")
.usernameParameter("email")
.passwordParameter("password")
)
// ...
}
这就是说允许对“/”、“/signup”、“/search”的
请求,而无需用户登录。对“/dashboard/**”的请求需要用户登录并具有“角色”行政”。
对任何其他端点的请求都需要用户登录。
这意味着对“/addReview”的请求需要用户登录。
在您描述的情况下,用户未登录,这就是不允许他们访问“/addReview”的原因。
Spring Security 阻止请求到达控制器,因为没有登录用户。
Spring Security 将谁通过身份验证的详细信息存储在SecurityContextHolder
.
查看提供的代码,SecurityContextHolder
从未填充过,因此从 Spring Security 的角度来看,没有人登录。
上面的“/signup”端点只是在视图(HTML 页面)上设置一些字段,而不是实际执行登录。
由于您已.formLogin()
在配置中启用,因此 Spring Security 提供了大部分登录功能。
您只需将用户名(在本例中为电子邮件)和密码发布到生成的“/”登录端点,框架将验证用户并填充SecurityContextHolder
.
<form th:action="@{/}" method="post">
<div>
<input type="email" name="email" id="inputEmail" placeholder="email" required>
</div>
<div>
<input type="password" name="password" id="inputPassword" placeholder="password" required>
</div>
<input type="submit" value="SIGN IN" />
</form>
然后,您可以仅将“/signup”端点用于注册,而不是将其与登录逻辑结合使用。
您可能还想研究Thymeleaf + Spring Security 集成。这将允许您在模板中获取用户名,而无需在控制器中进行设置。
<div>Logged in user: <span sec:authentication="name"></span></div>
我建议您不要禁用 CSRF 保护。这使您的应用程序容易受到CSRF 攻击。使用 Thymeleaf 时会自动包含CSRF 令牌,因此不需要更改代码,您的应用程序将更加安全。
推荐阅读
- node.js - 调试 babel-watch 输出时使用源映射
- java - 如何修复“找不到‘jnu’的类文件。”
- python - 使用 linspace 绘制的值绘制样本数而不是区间内的数字
- google-sheets - 有没有一种方法可以运行脚本而不必每次复制电子表格时重新授权它们?
- angular - 来自函数的 routerLink 链接
- c# - 如何在客户端类中使用非泛型接口的泛型方法?
- ios - 选择表视图行时调用两次 do(onNext:)
- python - 如何使用条件删除 y_train 数组中值的百分比
- python - 如何在 python 中使用 scikit-image graycomatrix() -function?
- ruby-on-rails - 支持多数据库的连接切换在 Rails 6.0.0.beta3 版本中不起作用