阅读spring security文档
This commit is contained in:
@@ -38,6 +38,10 @@
|
|||||||
- [将token持久化到数据库中](#将token持久化到数据库中)
|
- [将token持久化到数据库中](#将token持久化到数据库中)
|
||||||
- [RememberMe的接口及其实现](#rememberme的接口及其实现)
|
- [RememberMe的接口及其实现](#rememberme的接口及其实现)
|
||||||
- [TokenBasedRememberMeService](#tokenbasedremembermeservice)
|
- [TokenBasedRememberMeService](#tokenbasedremembermeservice)
|
||||||
|
- [匿名身份认证](#匿名身份认证)
|
||||||
|
- [匿名认证配置](#匿名认证配置)
|
||||||
|
- [处理logout](#处理logout)
|
||||||
|
- [自定义登出url](#自定义登出url)
|
||||||
|
|
||||||
|
|
||||||
# Spring Security
|
# Spring Security
|
||||||
@@ -732,5 +736,83 @@ RememberMeAuthenticationProvider rememberMeAuthenticationProvider() {
|
|||||||
return rememberMeAuthenticationProvider;
|
return rememberMeAuthenticationProvider;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
## 匿名身份认证
|
||||||
|
Spring Security中,采用了`deny-by-default`策略,用以适配如下场景:除少数资源外(如homepage、login页面等),访问其他所有的资源都需要进行身份认证。
|
||||||
|
|
||||||
|
Spring Security提供了匿名身份认证,对于“匿名身份认证”的用户,其实际和未经认证的用户没有任何区别。匿名认证只是为配置访问控制属性提供了更加便捷的方式,在匿名认证时,即使当前`SecurityContextHolder`中存在`anonymous authentication`对象,在调用一些servlet api例如`getCallerPrincipal`方法时,方法仍然会返回null。
|
||||||
|
|
||||||
|
在使用anonymous authentication时,Spring Security的SecurityContextHolder一定含有Authentication对象,即使用户未经认证,Authentication对象也不可能为空。
|
||||||
|
|
||||||
|
### 匿名认证配置
|
||||||
|
匿名认证在Spring Security中是默认被提供的,可以对其进行自定义或者关闭。
|
||||||
|
|
||||||
|
为了提供匿名认证特性,需要存在如下三个类:`AnonymousAuthenticationToken`、`AnonymousAuthenticationProvider`、`AnonymousAuthenticationFilter`。
|
||||||
|
- `AnonymousAuthenticationToken`:该类是`Authentication`的实现类,并且存储了该匿名实体所拥有的权限`GrantedAuthority`
|
||||||
|
- `AnonymousAuthenticationProvider`:该类被整合到`ProviderManager`的provider链中,故而`AnonymousAuthenticationToken`可以被支持进行处理
|
||||||
|
- `AnonymousAuthenticationFilter`:该filter被嵌入到常规的认证机制之后,如果在执行到该filter时,当前SecurityContextHolder中不存在Authentication,那么其会自动将`AnonymousAuthenticationToken`加入到SecurityContextHolder中。
|
||||||
|
|
||||||
|
定义filter和provider的方式如下所示,filter和provider共享相同的key,故而filter创建的token可以被provider接收:
|
||||||
|
```java
|
||||||
|
<bean id="anonymousAuthFilter"
|
||||||
|
class="org.springframework.security.web.authentication.AnonymousAuthenticationFilter">
|
||||||
|
<property name="key" value="foobar"/>
|
||||||
|
<property name="userAttribute" value="anonymousUser,ROLE_ANONYMOUS"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="anonymousAuthenticationProvider"
|
||||||
|
class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
|
||||||
|
<property name="key" value="foobar"/>
|
||||||
|
</bean>
|
||||||
|
```
|
||||||
|
|
||||||
|
`userAttribute`属性值,其格式为`usernameInTheAuthenticationToken,grantedAuthority[,grantedAuthority]`。
|
||||||
|
|
||||||
|
|
||||||
|
## 处理logout
|
||||||
|
如果当前项目的类路径中包含`spring-boot-starter-security`依赖,那么spring security会自动加入logout支持,针对`GET`和`POST`的`/logout`请求都会响应。
|
||||||
|
|
||||||
|
当通过get方式请求/logout时,spring security将展示一个登出页面。但如果csrf保护被关闭,那么不会展示登出确认页面,而是直接关闭。
|
||||||
|
|
||||||
|
当请求/logout时,将通过一系列logoutHandler来实现如下逻辑:
|
||||||
|
1. 将http session标记为失效(SecurityContextLogoutHandler)
|
||||||
|
2. 清空SecurityContextHolderStrategy (SecurityContextLogoutHandler)
|
||||||
|
3. 清空SecurityContextRepository(SecurityContextLogoutHandler)
|
||||||
|
4. 清空所有rememberMe authentication(TokenRememberMeServices / PersistentTokenRememberMeServices)
|
||||||
|
5. 清空任何csrf token (LogoutSuccessEventPublishingLogoutHandler)
|
||||||
|
6. 发送LogoutSuccessEvent(LogoutSuccessEventPublishingLogoutHandler)
|
||||||
|
|
||||||
|
### 自定义登出url
|
||||||
|
在filter chain中,logoutFilter位于AuthorizationFilter之前,故而没有必要显式的对/logout url执行permit操作(因为尚未执行到AuthorizationFilter之前,就会通过logoutFilter执行登出操作)。
|
||||||
|
|
||||||
|
但是,对于自定义的登出端口(默认情况下,logooutFilter只对/logout的请求进行处理),若url不为/logout,那么需要调用`permitAll`来让自定义登出端口可访问。
|
||||||
|
|
||||||
|
如果只是要修改spring security登出的url,可以通过如下方式进行修改,且不需要其他任何修改,其单单只是改变了logoutFilter匹配的url:
|
||||||
|
```java
|
||||||
|
http
|
||||||
|
.logout((logout) -> logout.logoutUrl("/my/logout/uri"))
|
||||||
|
```
|
||||||
|
|
||||||
|
但是,如果自定义了logout success endpoint(通过spring mvc建立的controller endpoint),那么需要为自定义的logout endpoint执行permit操作来允许用户访问。因为只有当spring security中的操作都完成后,才会指定自定义的endpoint操作。
|
||||||
|
|
||||||
|
可以通过如下方式为自定义的登出endpoint进行授权:
|
||||||
|
```java
|
||||||
|
http
|
||||||
|
.authorizeHttpRequests((authorize) -> authorize
|
||||||
|
.requestMatchers("/my/success/endpoint").permitAll()
|
||||||
|
// ...
|
||||||
|
)
|
||||||
|
.logout((logout) -> logout.logoutSuccessUrl("/my/success/endpoint"))
|
||||||
|
```
|
||||||
|
> logoutSuccessUrl为logout操作执行成功后,重定向到的url,该值默认为`/login?logout`。
|
||||||
|
>
|
||||||
|
> logoutUrl则是触发logout操作的url。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user