假设应用程序从使用JSP转向使用Themeleaf,本文将对Spring应用程序如何在登录页面、错误页面(login and error pages)使用Thymeleaf进行说明。本文讲述内容的代码,可以在GitHub上浏览和下载https://github.com/thymeleaf/thymeleafexamples-springsecurity
Spring Security文档:http://docs.spring.io/spring-security/site/reference.html
1.登录页面(Login pages)
使用 Spring Security可以指定任意URL作为登录页面,例如:
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login.html")
.failureUrl("/login-error.html")
.and()
.logout()
.logoutSuccessUrl("/index.html");
}
下面在一个Spring 的Controller中对上述代码相关请求的路径匹配上方法
@Controller
public class MainController {
...
// Login form
@RequestMapping("/login.html")
public String login() {
return "login.html";
}
// Login form with error
@RequestMapping("/login-error.html")
public String loginError(Model model) {
model.addAttribute("loginError", true);
return "login.html";
}
}
在上面的代码中,不管是/login.html还是/login-error.html最终使用的都是同一个模板( template)页面login.html。只不过在错误页面对应的方法中,给Model中的loginError赋值为Boolean值true,使其在login.html中可以获取,并显示Wrong user or password
login.html模板页面的代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login page</title>
</head>
<body>
<h1>Login page</h1>
<p th:if="${loginError}" class="error">Wrong user or password</p>
<form th:action="@{/login.html}" method="post">
<label for="username">Username</label>:
<input type="text" id="username" name="username" autofocus="autofocus" /> <br />
<label for="password">Password</label>:
<input type="password" id="password" name="password" /> <br />
<input type="submit" value="Log in" />
</form>
</body>
</html>
2.错误页面(Error page)
Exception Handling in Spring MVC异常处理:https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
基于Thymeleaf配置error page,基本不涉及Spring Security,只需要简单的添加异常处理ExceptionHandler到自己项目的Spring配置中,如下所示
@ControllerAdvice
public class ErrorController {
private static Logger logger = LoggerFactory.getLogger(ErrorController.class);
@ExceptionHandler(Throwable.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String exception(final Throwable throwable, final Model model) {
logger.error("Exception during execution of SpringSecurity application", throwable);
String errorMessage = (throwable != null ? throwable.getMessage() : "Unknown error");
model.addAttribute("errorMessage", errorMessage);
return "error";
}
}
error.html模板页面如下
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Error page</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="css/main.css" th:href="@{/css/main.css}" />
</head>
<body th:with="httpStatus=${T(org.springframework.http.HttpStatus).valueOf(#response.status)}">
<h1 th:text="|${httpStatus} - ${httpStatus.reasonPhrase}|">404</h1>
<p th:utext="${errorMessage}">Error java.lang.NullPointerException</p>
<a href="index.html" th:href="@{/index.html}">Back to Home Page</a>
</body>
</html>
上面代码中,使用Spring’s HttpStatus是为了获取响应状态(
response status)的详细信息。
@ResponseStatus
正常情况下,当一个web request导致服务器端返回一个HTTP 500的响应时,相应异常将会被抛出。然而,任何自己编写的异常处理均可以被@ResponseStatus标注,该标注支持所有的HTTP status code。当一个被@ResponseStatus标注的异常在项目的某Controller方法被抛出时,它会自动生成该自定义异常处理类中定义的合适的http响应和指定的响应码,然后将其返回。例如,下面是一个自定义的异常处理类,并使用@ResponseStatus进行标注。
@ResponseStatus(value=HttpStatus.NOT_FOUND, reason="No such Order") // 404
public class OrderNotFoundException extends RuntimeException {
// ...
}
下面的这段代码恰好使用了上面代码中自定义的异常处理
@RequestMapping(value="/orders/{id}", method=GET)
public String showOrder(@PathVariable("id") long id, Model model) {
Order order = orderRepository.findOrderById(id);
if (order == null) throw new OrderNotFoundException(id);
model.addAttribute(order);
return "orderDetail";
}
此时,若有一个不存在的order id出现在request请求的url中,则一个类似于404的经过我们自定义异常处理类处理之后的response将会被返回。
@ControllerAdvice+@ExceptionHandler实现Controller层全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
@ResponseBody
String handleException(){
return "Exception Deal!";
}
}
上述代码将会处理Controller层抛出的Exception及其子类对应的异常。若注解为@ExceptionHandler(Throwable.class)则可以处理Controller层抛出的Throwable对应的相关异常。
3.Spring安全方言(Spring Security Dialect)
Spring Security 3 integration module https://github.com/thymeleaf/thymeleaf-extras-springsecurity
Spring security taglib https://docs.spring.io/spring-security/site/docs/4.2.x/reference/html/taglibs.html
在下面例子中使用Spring的安全方言去显示已登录用户的认证信息,针对不同的角色显示不同的内容。
sec:authorize 当其属性表达式值为true的时候,将会显示相关设置的内容,代码如下
<div sec:authorize="isAuthenticated()">
This content is only shown to authenticated users.
</div>
<div sec:authorize="hasRole('ROLE_ADMIN')">
This content is only shown to administrators.
</div>
<div sec:authorize="hasRole('ROLE_USER')">
This content is only shown to users.
</div>
sec:authentication属性用于输出已登录用户的用户名和角色
Logged user: <span sec:authentication="name">Bob</span>
Roles: <span sec:authentication="principal.authorities">[ROLE_USER, ROLE_ADMIN]</span>
参考链接:https://www.thymeleaf.org/doc/articles/springsecurity.html