4.3 保护web 请求
4.3 保护web 请求
要配置这些安全规则,需要介绍一下
@Override
protected void configure(HttpSecurity http) throws Exception {
...
}
这个
- 在允许服务请求之前,需要满足特定的安全条件
- 配置自定义登录页面
- 使用户能够退出应用程序
- 配置跨站请求伪造保护
拦截请求以确保用户拥有适当的权限是配置
4.3.1 保护请求
需要确保
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/design", "/orders")
.hasRole("ROLE_USER")
.antMatchers(“/”, "/**").permitAll();
}
对
- 对于
/design 和/orders 的请求应该是授予ROLE_USER 权限的用户的请求。 - 所有的请求都应该被允许给所有的用户。
这些规则的顺序很重要。首先声明的安全规则优先于较低级别声明的安全规则。如果交换这两个安全规则的顺序,所有请求都将应用
表
方法 | 做了什么 |
---|---|
access(String) | 如果 |
anonymous() | 默认用户允许访问 |
authenticated() | 认证用户允许访问 |
denyAll() | 无条件拒绝所有访问 |
fullyAuthenticated() | 如果用户是完全授权的(不是记住用户 |
hasAnyAuthority(String…) | 如果用户有任意给定的权限,则允许访问 |
hasAnyRole(String…) | 如果用户有任意给定的角色,则允许访问 |
hasAuthority(String) | 如果用户有给定的权限,则允许访问 |
hasIpAddress(String) | 来自给定 |
hasRole(String) | 如果用户有给定的角色,则允许访问 |
not() | 拒绝任何其他访问方法 |
permitAll() | 无条件允许访问 |
rememberMe() | 允许认证了的同时标记了记住我的用户访问 |
表
表
意指什么 | |
---|---|
authentication | 用户认证对象 |
denyAll | 通常值为 |
hasAnyRole(list of roles) | 如果用户有任何给定的角色,则为 |
hasRole(role) | 如果用户有给定的角色,则为 |
hasIpAddress(IP Address) | 如果请求来自给定 |
isAnonymous() | 如果用户是默认用户,则为 |
isAuthenticated() | 如果用户是认证了的,则为 |
isFullyAuthenticated() | 如果用户被完全认证了的(不是使用记住我进行认证 |
isRememberMe() | 如果用户被标记为记住我后认证了,则为 |
permitAll() | 通常值为 |
principal | 用户 |
表
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/design", "/orders")
.access("hasRole('ROLE_USER')")
.antMatchers(“/”, "/**").access("permitAll");
}
乍一看,这似乎没什么大不了的。毕竟,这些表达式只反映了已经对方法调用所做的工作。但是表达式可以灵活得多。例如,假设(出于某种疯狂的原因)只想允许具有
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/design", "/orders")
.access("hasRole('ROLE_USER') && " +
"T(java.util.Calendar).getInstance().get("+
"T(java.util.Calendar).DAY_OF_WEEK) == " +
"T(java.util.Calendar).TUESDAY")
.antMatchers(“/”, "/**").access("permitAll");
}
使用基于
只需使用
4.3.2 创建用户登录页面
默认的登录页面比您开始时使用的笨拙的
要替换内置的登录页面,首先需要告诉
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/design", "/orders")
.access("hasRole('ROLE_USER')")
.antMatchers(“/”, "/**").access("permitAll")
.and()
.formLogin()
.loginPage("/login");
}
请注意,在调用
连接之后,调用
现在需要提供一个控制器来处理该路径上的请求。因为你的登录页面非常简单 —— 除了一个视图什么都没有 —— 在
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
registry.addViewController("/login");
}
最后,需要定义
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Taco Cloud</title>
</head>
<body>
<h1>Login</h1>
<img th:src="@{/images/TacoCloud.png}" />
<div th:if="${error}">
Unable to login. Check your username and password.
</div>
<p>New here? Click<a th:href="@{/register}">here</a> to register.</p>
<!-- tag::thAction[] -->
<form method="POST" th:action="@{/login}" id="loginForm">
<!-- end::thAction[] -->
<label for="username">Username: </label>
<input type="text" name="username" id="username" /><br />
<label for="password">Password: </label>
<input type="password" name="password" id="password" /><br />
<input type="submit" value="Login" />
</form>
</body>
</html>
关于这个登录页面需要注意的关键事情是,它发布到的路径以及用户名和密码字段的名称。默认情况下,
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/authenticate")
.usernameParameter("user")
.passwordParameter("pwd")
这里,指定
默认情况下,当
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/design")
按照这里的配置,如果用户在直接进入登录页面后成功登录,那么他们将被引导到
另外,可以强制用户在登录后进入设计页面,即使他们在登录之前已经在其他地方导航,方法是将
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/design", true)
现在已经处理了自定义登录页面,让我们来看看身份验证的另一面 —— 如何让用户登出。
4.3.3 登出
与登录应用程序同样重要的是登出。要启用登出功能,只需调用
.and()
.logout()
.logoutSuccessUrl("/")
这将设置一个安全筛选器来拦截发送到
<form method="POST" th:action="@{/logout}">
<input type="submit" value="Logout" />
</form>
当用户单击按钮时,他们的
.and()
.logout()
.logoutSuccessUrl("/")
在这个例子中,用户在登出后将被跳转到主页。
4.3.4 阻止跨站请求伪造攻击
跨站请求伪造(CSRF)是一种常见的安全攻击。它涉及到让用户在一个恶意设计的
为了防止此类攻击,应用程序可以在显示表单时生成
幸运的是,
<input type="hidden" name="_csrf" th:value="${_csrf.token}" />
如果使用
在