使用 Thymeleaf 与来自控制器的 html 文件交互
Interacting with html file from controller using Thymeleaf
我目前正在尝试创建一个控制器来使用 Thymeleaf 与 html 文件进行交互。一段时间后,我注意到我的控制器(更具体地说是 @PostMapping)可能根本没有与我的 html 页面交互。我认为这是因为无论我将什么输入设置为 email/password(正确或不正确),它总是 link 我(/login?error)。我测试了一个简单的条件语句,一旦 Post 请求被调用,它会在 html 页面上打印“HERE”,以查看是否确实如此。打印永远不会发生。 post 的目的是理解为什么忽略这个简单的 post 请求。由于我提出了一个简单的 Post 请求,因此我假设无论如何都会打印“此处”。
我的html代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Login Page</title>
</head>
<body>
<form th:action="@{/login}" th:object="${user}" method="post">
<div th:if="${here}">
<p>HERE</p>
</div>
<div>
<label>Email</label>
<input type="text" th:field="*{email}">
</div>
<div>
<label>Password</label>
<input type="text" th:field="*{password}" placeholder="Password">
</div>
<input type="submit" value="submit"/>
</form>
</body>
</html>
我的控制器class
@Controller
public class UserController {
UserRepository userRepo;
UserService userService;
@GetMapping("/login")
public String login(Model model) {
model.addAttribute("user", new User());
return "login";
}
@PostMapping("/login")
public String loginUser(@ModelAttribute("user") User user, Model model) {
model.addAttribute("here", true);
return "login";
}
}
我的 Spring 安全配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
private final UserService userService;
private final BCryptPasswordEncoder passwordEncoder;
public WebSecurityConfig(UserService userService, BCryptPasswordEncoder passwordEncoder) {
this.userService = userService;
this.passwordEncoder = passwordEncoder;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests()
.antMatchers("/registration/**", "/login")
.permitAll()
.anyRequest()
.authenticated().and()
.formLogin().loginPage("/login").permitAll();;
return http.build();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
}
@Bean
public DaoAuthenticationProvider daoAutenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(userService);
return provider;
}
}
来吧,首先你需要一个用于你的 home
页面的控制器..
@RequestMapping("/home")
public String home() {
return "home";
}
然后需要将security
配置为:
1 - 考虑 email
和 password
进行身份验证。
2 - 将 home
页面配置为默认登录页面。
3 - 配置注销页面,spring默认是/login?logout
,但我会告诉你一个方法return一个变量作为参数。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests()
.antMatchers("/registration/**", "/login")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("email")
.passwordParameter("password")
.defaultSuccessUrl("/home", true)
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.logoutSuccessUrl("/login?unverified-email"); //unverified email variable.
return http.build();
}
完成后,您的登录应该会成功并转到主页。
验证邮箱是否通过验证,首先要验证登录,这样才能正确找到用户,通过用户验证后,就可以查看邮箱是否通过验证了。最简单的方法是,当您被重定向到 /home
时,您可以获取用户名并验证电子邮件是否已通过验证,如果没有,您将重定向回 /login?unverified-email
.
那么你的控制器看起来像这样:
UserService userService;
@RequestMapping("/home")
public String home() {
User user = userService.getUser();
if(!user.verified)
return "redirect:/login?unverified-email";
return "home";
}
UserService
public User getUser() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String user;
if (principal instanceof UserDetails) {
user = ((UserDetails)principal).getUsername();
} else {
user = principal.toString();
}
return repository.findByEmail(user);
}
并且在登录页面上,要显示未验证的电子邮件消息,您可以添加如下内容:
<div th:if="${param.unverified-email}">
User not confirmed, please confirm your Email.
</div>
当然,也许这不是最好的方法,但它对我有用。
因此,为了处理不正确的登录,您有多种选择。要指定处理登录错误的不同页面(与登录页面不同),您可以在 Spring security.
中调用 failureUrl("/loginFailure")
但是如果您仍想使用相同的登录名 page/request(例如 /login )来处理登录错误,您可以通过为 GET /login 提供一个端点来做到这一点(注意 POST /login 由 Spring 安全性处理,正如评论中提到的那样),您可以在其中检查 url 是否包含名为“error”的参数。
@RequestMapping("/login")
public ModelAndView loginUser(ModelAndView mv,
HttpServletRequest request) {
//for failed logins, the query string is equal to error
String queryStr = request.getQueryString();
if(queryStr != null && "error".equals(queryStr)){
mv.addObject("errorMsg", "wrong credentials");
mv.setViewName("errorPage");
}else {
//process other scenarios
}
return mv;
}
现在,在 Thymeleaf 中,您可以简单地检查 errorMsg 的值并向用户显示适当的消息。
我目前正在尝试创建一个控制器来使用 Thymeleaf 与 html 文件进行交互。一段时间后,我注意到我的控制器(更具体地说是 @PostMapping)可能根本没有与我的 html 页面交互。我认为这是因为无论我将什么输入设置为 email/password(正确或不正确),它总是 link 我(/login?error)。我测试了一个简单的条件语句,一旦 Post 请求被调用,它会在 html 页面上打印“HERE”,以查看是否确实如此。打印永远不会发生。 post 的目的是理解为什么忽略这个简单的 post 请求。由于我提出了一个简单的 Post 请求,因此我假设无论如何都会打印“此处”。
我的html代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Login Page</title>
</head>
<body>
<form th:action="@{/login}" th:object="${user}" method="post">
<div th:if="${here}">
<p>HERE</p>
</div>
<div>
<label>Email</label>
<input type="text" th:field="*{email}">
</div>
<div>
<label>Password</label>
<input type="text" th:field="*{password}" placeholder="Password">
</div>
<input type="submit" value="submit"/>
</form>
</body>
</html>
我的控制器class
@Controller
public class UserController {
UserRepository userRepo;
UserService userService;
@GetMapping("/login")
public String login(Model model) {
model.addAttribute("user", new User());
return "login";
}
@PostMapping("/login")
public String loginUser(@ModelAttribute("user") User user, Model model) {
model.addAttribute("here", true);
return "login";
}
}
我的 Spring 安全配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
private final UserService userService;
private final BCryptPasswordEncoder passwordEncoder;
public WebSecurityConfig(UserService userService, BCryptPasswordEncoder passwordEncoder) {
this.userService = userService;
this.passwordEncoder = passwordEncoder;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests()
.antMatchers("/registration/**", "/login")
.permitAll()
.anyRequest()
.authenticated().and()
.formLogin().loginPage("/login").permitAll();;
return http.build();
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
}
@Bean
public DaoAuthenticationProvider daoAutenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(userService);
return provider;
}
}
来吧,首先你需要一个用于你的 home
页面的控制器..
@RequestMapping("/home")
public String home() {
return "home";
}
然后需要将security
配置为:
1 - 考虑 email
和 password
进行身份验证。
2 - 将 home
页面配置为默认登录页面。
3 - 配置注销页面,spring默认是/login?logout
,但我会告诉你一个方法return一个变量作为参数。
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeHttpRequests()
.antMatchers("/registration/**", "/login")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("email")
.passwordParameter("password")
.defaultSuccessUrl("/home", true)
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/login?logout")
.logoutSuccessUrl("/login?unverified-email"); //unverified email variable.
return http.build();
}
完成后,您的登录应该会成功并转到主页。
验证邮箱是否通过验证,首先要验证登录,这样才能正确找到用户,通过用户验证后,就可以查看邮箱是否通过验证了。最简单的方法是,当您被重定向到 /home
时,您可以获取用户名并验证电子邮件是否已通过验证,如果没有,您将重定向回 /login?unverified-email
.
那么你的控制器看起来像这样:
UserService userService;
@RequestMapping("/home")
public String home() {
User user = userService.getUser();
if(!user.verified)
return "redirect:/login?unverified-email";
return "home";
}
UserService
public User getUser() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String user;
if (principal instanceof UserDetails) {
user = ((UserDetails)principal).getUsername();
} else {
user = principal.toString();
}
return repository.findByEmail(user);
}
并且在登录页面上,要显示未验证的电子邮件消息,您可以添加如下内容:
<div th:if="${param.unverified-email}">
User not confirmed, please confirm your Email.
</div>
当然,也许这不是最好的方法,但它对我有用。
因此,为了处理不正确的登录,您有多种选择。要指定处理登录错误的不同页面(与登录页面不同),您可以在 Spring security.
中调用 failureUrl("/loginFailure")但是如果您仍想使用相同的登录名 page/request(例如 /login )来处理登录错误,您可以通过为 GET /login 提供一个端点来做到这一点(注意 POST /login 由 Spring 安全性处理,正如评论中提到的那样),您可以在其中检查 url 是否包含名为“error”的参数。
@RequestMapping("/login")
public ModelAndView loginUser(ModelAndView mv,
HttpServletRequest request) {
//for failed logins, the query string is equal to error
String queryStr = request.getQueryString();
if(queryStr != null && "error".equals(queryStr)){
mv.addObject("errorMsg", "wrong credentials");
mv.setViewName("errorPage");
}else {
//process other scenarios
}
return mv;
}
现在,在 Thymeleaf 中,您可以简单地检查 errorMsg 的值并向用户显示适当的消息。