# 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配置过滤器链 ![image-20210218211058535](https://img-blog.csdnimg.cn/img_convert/5092ce6ec094ec58d7933c8e8dd1979d.png) 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中。 ![image-20210218222343101](https://img-blog.csdnimg.cn/img_convert/e21e41f68c8ca166cafacb8f004438e3.png) ![image-20210218221954979](https://img-blog.csdnimg.cn/img_convert/52a4d71c30769a7b8772bc4449c9e716.png) #### 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) ``` ![image-20210220164732377](https://img-blog.csdnimg.cn/img_convert/886645b2acf38543a41175bee713e9a1.png) 用户发送请求到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`:表示访问对应方法时所应具有的角色 ![image-20210220213837545](https://img-blog.csdnimg.cn/img_convert/50eea0b92d7cf8d2b14aacd283d85bce.png) - `@PermitAll`:允许所有角色进行访问 ![image-20210220213903538](https://img-blog.csdnimg.cn/img_convert/238666807d64146c7195d90a2b344790.png) - `@DenyAll`:所有角色都不可以访问 ![image-20210220213926747](https://img-blog.csdnimg.cn/img_convert/d327d2c874c175a13fc1382bcf236542.png) - `基于Security自带的@Sourced注解` - `@Sourced`:允许指定角色访问 ![image-20210220214001583](https://img-blog.csdnimg.cn/img_convert/d9e13de692c2c28b8ad7b97233ee1ed1.png) - `基于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`:该注解调用方法前验证权限 ![image-20210220215006437](https://img-blog.csdnimg.cn/img_convert/030c8934ed3e29083e8bdc7521fa9f0a.png) - `@PstAuthorize`:调用方法后调用权限验证 ![image-20210220215055856](https://img-blog.csdnimg.cn/img_convert/9c818f730b8ecf4714cc6424cb982b9b.png) - `@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) { ... } ```