# ssm_spring_security
**Repository Path**: xiao_long_ya/ssm_spring_security
## Basic Information
- **Project Name**: ssm_spring_security
- **Description**: ssm整合SpringSecurity
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 2
- **Forks**: 0
- **Created**: 2021-02-19
- **Last Updated**: 2022-03-31
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# SSM整合SpringSecurity
#### 1.SpringSecurity权限认证框架
权限管理主要包含两个部分**认证:**和**授权**
- `认证`:通过用户名和密码成功登陆系统后,让系统得到当前用户的角色身份。
- `授权`:系统根据当前用户的角色,给其授予对应可以操作的权限资源。
而完成权限管理一般所需要三个对象
- `用户`
- `角色`
- `权限`
**用户与角色多对多关系,角色与权限多对多关系**
权限管理的三个概念
- `principal(主体)`:简单的说就是当前用户
- `authentication(认证)`:对用户进行验证,可以说是登录操作
- `authorization(授权)`:对验证成功的用户进行授权
#### 2.SpringSecurity的过滤器链
在web.xml配置过滤器链

SpringSecurity默认加载15个核心的过滤器
1. `org.springframework.security.web.context.SecurityContextPersistenceFilter`
> SecurityContextPersistenceFilter主要是使用SecurityContextRepository在session中保存或更新一个
>
> SecurityContext,并将SecurityContext给以后的过滤器使用,来为后续fifilter建立所需的上下文。
>
> SecurityContext中存储了当前用户的认证以及权限信息。
2. `org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter`
> WebAsyncManagerIntegrationFilter`此过滤器用于集成SecurityContext到Spring异步执行机制中的WebAsyncManager
3. `org.springframework.security.web.header.HeaderWriterFilter`
> 向请求的Header中添加相应的信息,可在http标签内部使用security:headers来控制
4. `org.springframework.security.web.csrf.CsrfFilter`
> csrf又称跨域请求伪造,SpringSecurity会对所有post请求验证是否包含系统生成的csrf的token信息,
>
> 如果不包含,则报错。起到防止csrf攻击的效果。开启了csrf前端需提交一个_csrf的字段
>
>
5. `org.springframework.security.web.authentication.logout.LogoutFilter`
> 匹配URL为/logout的请求,实现用户退出,清除认证信息。
6. `org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter`
> 认证操作全靠这个过滤器,默认匹配URL为/login且必须为POST请求。
7. `org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter`
> 如果没有在配置文件中指定认证页面,则由该过滤器生成一个默认认证页面。
8. `org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter`
> 由此过滤器可以生产一个默认的退出登录页面
9. `org.springframework.security.web.authentication.www.BasicAuthenticationFilter`
> 此过滤器会自动解析HTTP请求中头部名字为Authentication,且以Basic开头的头信息。
10. `org.springframework.security.web.savedrequest.RequestCacheAwareFilter`
> 通过HttpSessionRequestCache内部维护了一个RequestCache,用于缓存HttpServletRequest
11. `org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter`
> 针对ServletRequest进行了一次包装,使得request具有更加丰富的API
12. `org.springframework.security.web.authentication.AnonymousAuthenticationFilter`
> 当SecurityContextHolder中认证信息为空,则会创建一个匿名用户存入到SecurityContextHolder中。
>
> spring security为了兼容未登录的访问,也走了一套认证流程,只不过是一个匿名的身份。
13. `org.springframework.security.web.session.SessionManagementFilter`
> SecurityContextRepository限制同一用户开启多个会话的数量
14. `org.springframework.security.web.access.ExceptionTranslationFilter`
> 异常转换过滤器位于整个springSecurityFilterChain的后方,用来转换整个链路中出现的异常
15. `org.springframework.security.web.access.intercept.FilterSecurityInterceptor`
> 获取所配置资源访问的授权信息,根据SecurityContextHolder中存储的用户信息来决定其是否有权限。
SpringSecurity默认加载15个过滤器,可以动态的配置新增或者减少过滤器,所有的过滤器都被封装到SecurityFilterChain对象中,SecurityFilterChain是一个接口它的实现类是DefaultSecurityFilterChain,这是真正的过滤器链。
#### 3.Spring Security的CSRF防护机制
Spring Security默认开启CSRF保护,
“GET”,”HEAD”,”TRACE”,”OPTIONS”四种请求不用携带CSRF token,token其余的请求需要携带token,token可以放在请求参数或者header中。


#### 4.Spring Security的记住我
记住需要在数据库新建一个表存放token,sql语句如下
```sql
create table persistent_logins (username varchar(64) not null,
series varchar(64) primary key,
token varchar(64) not null,
last_used timestamp not null)
```

用户发送请求到UsernamePasswordAuthenticationFilter,当用户认证成功以后,会调一个RemeberMeService这样一个服务。这个服务里面有一个TokenRepository,会生成一个Token,将这个Token写入到浏览器的Cookie里面,同时TokenRepository把生成的Token写入到数据库里面(还有用户名)。当用户再次访问的时候请求会在经过过滤器链的时候会经过RemberMeAuenticationFilter(读取Cookie中的Token)给RemberMeService,RemberMeService会根据Token到数据库里面去查。如果有记录,就会把Username用户名取出来,取出来之后会调用UserDetailsService,获取用户信息,然后把用户信息放入到SecurityContext里面。
#### 5.Spring Security的权限配置
```xml
```
**使用ssm配置文件时,ContextLoaderListener监听器加载的applicationContext.xml配置文件中配置service层和dao层的自动扫描,这是父容器,而由DispatcherServlet加载的spring-mvc.xml应该配置Controler的自动扫描,这很重要[https://blog.csdn.net/qq_35571554/article/details/82464236](https://blog.csdn.net/qq_35571554/article/details/82464236)**
- `基于jsr250的权限注解`:
- `@RolesAllowed`:表示访问对应方法时所应具有的角色

- `@PermitAll`:允许所有角色进行访问

- `@DenyAll`:所有角色都不可以访问

- `基于Security自带的@Sourced注解`
- `@Sourced`:允许指定角色访问

- `基于SPEL表达式的权限注解`@PreAuthorize、@PostAuthorize、@PreFilter和 @PostFilter;
表达式根对象的基类是SecurityExpressionRoot。这提供了一些在Web和方法安全性中都可用的通用表达式。常用的内置表达式如下
| Expression | Description |
| :----------------------------------------------------------- | :----------------------------------------------------------- |
| `hasRole(String role)` | Returns `true` if the current principal has the specified role.For example, `hasRole('admin')`By default if the supplied role does not start with 'ROLE_' it will be added. This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. |
| `hasAnyRole(String… roles)` | Returns `true` if the current principal has any of the supplied roles (given as a comma-separated list of strings).For example, `hasAnyRole('admin', 'user')`By default if the supplied role does not start with 'ROLE_' it will be added. This can be customized by modifying the `defaultRolePrefix` on `DefaultWebSecurityExpressionHandler`. |
| `hasAuthority(String authority)` | Returns `true` if the current principal has the specified authority.For example, `hasAuthority('read')` |
| `hasAnyAuthority(String… authorities)` | Returns `true` if the current principal has any of the supplied authorities (given as a comma-separated list of strings)For example, `hasAnyAuthority('read', 'write')` |
| `principal` | Allows direct access to the principal object representing the current user |
| `authentication` | Allows direct access to the current `Authentication` object obtained from the `SecurityContext` |
| `permitAll` | Always evaluates to `true` |
| `denyAll` | Always evaluates to `false` |
| `isAnonymous()` | Returns `true` if the current principal is an anonymous user |
| `isRememberMe()` | Returns `true` if the current principal is a remember-me user |
| `isAuthenticated()` | Returns `true` if the user is not anonymous |
| `isFullyAuthenticated()` | Returns `true` if the user is not an anonymous or a remember-me user |
| `hasPermission(Object target, Object permission)` | Returns `true` if the user has access to the provided target for the given permission. For example, `hasPermission(domainObject, 'read')` |
| `hasPermission(Object targetId, String targetType, Object permission)` | Returns `true` if the user has access to the provided target for the given permission. For example, `hasPermission(1, 'com.example.domain.Message', 'read')` |
- `@PreAuthorize`:该注解调用方法前验证权限

- `@PstAuthorize`:调用方法后调用权限验证

- `@PreFilter和@PostFilter`:
使用@PreFilter和@PostFilter可以对集合类型的参数或返回值进行过滤。使用@PreFilter和@PostFilter时,Spring Security将移除使对应表达式的结果为false的元素。
```java
@PostFilter("filterObject.id%2==0")
public List findAll() {
List userList = new ArrayList();
User user;
for (int i=0; i<10; i++) {
user = new User();
user.setId(i);
userList.add(user);
}
return userList;
}
```
述代码表示将对返回结果中id不为偶数的user进行移除。filterObject是使用@PreFilter和@PostFilter时的一个内置表达式,表示集合中的当前对象。当@PreFilter标注的方法拥有多个集合类型的参数时,需要通过@PreFilter的filterTarget属性指定当前@PreFilter是针对哪个参数进行过滤的。如下:
```java
@PreFilter(filterTarget="ids", value="filterObject%2==0")
public void delete(List ids, List usernames) {
...
}
```