最近学 Thymeleaf 的时候做一个登录的页面,后端是用 Shiro 进行认证的,但不知道为什么 BindingResult 里面的 FieldError 一直不显示,如果不用 Shiro 的话就可以,有人遇到过一样的情况吗? 附上关键的代码(篇幅有点长):
ShiroConfig.java:
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/**", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public AccountRealm accountRealm() {
AccountRealm accountRealm = new AccountRealm();
return accountRealm;
}
@Bean
public SessionsSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(accountRealm());
return securityManager;
}
}
AccountRealm.java
public class AccountRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username = (String) authenticationToken.getPrincipal();
String password = new String((char[]) authenticationToken.getCredentials());
if (!username.equals("admin")) {
throw new UnknownAccountException("用户不存在");
}
if (!"root.".equals(password)) {
throw new IncorrectCredentialsException("密码不正确");
}
AccountDO account = new AccountDO(1, username, password);
return new SimpleAuthenticationInfo(account, password, getName());
}
}
AccountDO.java
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AccountDO {
private Integer id;
@Size(min = 5, message = "用户名长度不能小于 5")
@NotBlank(message = "用户名不能为空")
private String username;
@Size(min = 4, max = 18, message = "密码长度为 4 到 18 位")
@NotBlank(message = "密码不能为空")
private String password;
}
AccountController.java
@Controller
@Slf4j
public class AccountController {
@GetMapping(value = "/login")
public String login(Model model) {
AccountDO account = new AccountDO();
model.addAttribute("account", account);
return "login";
}
@PostMapping(value = "/login")
public String login(@Valid AccountDO account,
BindingResult bindingResult,
Model model) {
model.addAttribute("account", account);
if (bindingResult.hasErrors()) {
bindingResult.getAllErrors().forEach((error) -> log.info(error.getDefaultMessage()));
return "login";
}
UsernamePasswordToken token = new UsernamePasswordToken(account.getUsername(), account.getPassword());
Subject subject = SecurityUtils.getSubject();
try {
subject.login(token);
AccountDO accountDO = (AccountDO) subject.getPrincipal();
log.info("登录成功:" + accountDO.getUsername());
return "index";
} catch (UnknownAccountException e) {
FieldError fieldError = new FieldError("account", "username", e.getMessage());
bindingResult.addError(fieldError);
log.info(e.getMessage());
return "login";
} catch (AuthenticationException e) {
FieldError fieldError = new FieldError("account", "password", e.getMessage());
bindingResult.addError(fieldError);
log.info(e.getMessage());
return "login";
}
}
}
login.html
<form th:action="@{/login}" method="post" th:object="${account}">
<table>
<tbody>
<tr>
<td>用户名</td>
<td><input type="text" name="username" th:value="*{username}" required></td>
<td><span th:if="${#fields.hasErrors('username')}" th:errors="*{username}"></span></td>
</tr>
<tr>
<td>密码</td>
<td><input type="password" name="password" th:value="*{password}" required></td>
<td><span th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></span></td>
</tr>
<tr>
<td><button type="submit">登录</button></td>
</tr>
</tbody>
</table>
</form>
不管是抛异常的时候加入的 FieldError 还是实体类验证时 BindingResult 里的 FieldError 都不能显示。试了一下不用 Shiro 的话可以显示,这是为什么呢?