定义
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,充分利用了spirngIOC与AOP功能,为应用系统提供声明式(可以使用注解)的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。
作用
Spring Security是一个安全框架,只要用来做权限的校验,提到权限校验,就要引出两个关键词——认证和授权。
认证和授权
- 认证:认证就是系统提供的用于验证用户身份的功能,一般在登录的时候就在进行认证。用于判断当前登录的用户的角色信息。
- 授权:在用户认证登录成功后需要为用户授权,权限一般根据当前登录的用户从数据库中查询其对应的权限,从而授予;授予权限其实就是指定用户能够进行哪些操作,而没有权限的操作就不能进行。如该用户没有修改权限,那么就不能执行修改操作。
原理
可以看到,在spring security内部其实就是通过一个过滤器链来实现认证流程的,比如说,UsernamePasswordAuthenticationFilter过滤器
就是拦截我们通过表单提交接口提交的用户名和密码,如果是基本提交,就会被BasicAuthenticationFilter过滤器
所拦截,最后的橙色FilterSecurityInterceptor过滤器
首先判断我们当前请求的url是否需要认证,如果需要认证,那么就看当前请求是否已经认证,是的话就放行到我们要访问的接口,否则重定向到认证页面。
使用
-
在web.xml文件中配置spring security过滤器链,并设置要拦截的请求
<!--配置spring-security过滤器链(委派过滤器)--> <filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <!--配置要拦截的请求地址--> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <!--拦截所有请求--> <url-pattern>/*</url-pattern> </filter-mapping> <!--配置servlet--> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--加载springMVC映射文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spring-mvc.xml,classpath*:spring-security.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
-
创建
spring-security.xml
文件,在其中主要配置Spring Security的拦截规则和认证管理器spring-security.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!--指定不需要权限校验的资源,pattern:指定资源的请求路径--> <security:http security="none" pattern="/login.html"/> <security:http security="none" pattern="/css/**"/> <security:http security="none" pattern="/img/**"/> <security:http security="none" pattern="/js/**"/> <security:http security="none" pattern="/plugins/**"/> <!-- 配置要进行拦截后权限校验的资源请求 auto-config:自动配置某些配置项,并且会提供一个默认的登录界面(可以自己指定一个登陆界面),需要用户进行登录认证 use-expressions="true":是否使用权限校验表达式 --> <security:http auto-config="true" use-expressions="true"> <!-- 配置拦截请求地址与校验权限 pattern:要拦截的请求路径 access:指定需要的权限,当认证用户时,由相应的权限才能访问pattern配置的页面 isAuthenticated():判断是否已认证(登录成功就是通过认证) --> <security:intercept-url pattern="/pages/**" access="isAuthenticated()"/> <!-- 自定义登录页面表单 login-page:自定义登录页面的地址 username-parameter:表单中用户名输入框的name属性值,要和此处对应 password-parameter:表单中密码输入框的name属性值,要和此处对应 default-target-url:登录认证成功后的跳转页面链接 authentication-failure-url:认证失败后跳转的页面链接 login-processing-url:表单提交链接 --> <security:form-login login-page="/login.html" username-parameter="username" password-parameter="password" default-target-url="/pages/main.html" authentication-failure-url="/login.html" login-processing-url="/login"/> <!-- 配置登出(退出) logout-url:登出地址 logout-success-url:成功登出后的跳转地址 invalidate-session:是否销毁session,因为spring-security底层就是使用session来存储登录用户的信息的。 --> <security:logout logout-url="/logout" logout-success-url="/login.html" invalidate-session="true"/> <!--如果需要使用自定义的登录页面,需要禁用csrf过滤器--> <security:csrf disabled="true"/> <!--设置通过iframe访问的页面可以访问,默认为不可访问--> <security:headers> <!-- policy:策略方针 SAMEORIGIN:同源请求 ALLOW-FROM:允许 DEDY:拒绝 --> <security:frame-options policy="SAMEORIGIN"/> </security:headers> </security:http> <!--配置密码加密bean--> <bean id="bCryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> <!--配置权限认证管理器--> <security:authentication-manager> <!-- 配置权限认证提供者 user-service-ref:引用注入到spring容器的bean,这个bean要实现UserDetailsService接口 --> <security:authentication-provider user-service-ref="springSecurityService"> <!--配置密码加密策略,因为保存到数据库中的密码是加密后的,所以在对比的时候,获取的登录时的密码需要加密后在做对比--> <security:password-encoder ref="bCryptPasswordEncoder"/> </security:authentication-provider> </security:authentication-manager> <!--开启注解权限控制方式--> <security:global-method-security pre-post-annotations="enabled"/> </beans>
注意,除了配置
spring-security.xml
文件外,还要配置spring的配置文件,因为后面的类需要配置到spring容器中。 -
自定义java类,需要实现
UserDetailsService
接口SpringSecurityService.java类名随意
/** * 认证用户及授权 */ @Component public class SpringSecurityService implements UserDetailsService { @Reference private UserService userService; /** * 授权方法,该方法会在用户进行登录认证的时候被spring-security自动执行 * * @param username * @return * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //根据用户名查询用户数据 User user = userService.findByUserName(username); //判断用户是否存在 if (user == null) { return null; } //根据用户id,查询该用户拥有的所有角色与权限 List<String> list = userService.findAllRoleAndPermissionByUserId(user.getId()); //给用户授权 //创建权限集合 List<GrantedAuthority> grantedAuthorityList = new ArrayList(); //将从数据库中查询到的权限封装到集合中 list.forEach(element -> { grantedAuthorityList.add(new SimpleGrantedAuthority(element)); }); //使用spring-security提供的user类,完成用户的认证和权限(在这里会完成密码的校验,获取用户在登录时提交的密码与数据库中保存的密码做对比,如果密码相同则完成认证,并赋予当前用户权限) org.springframework.security.core.userdetails.User securityUser = new org.springframework.security.core.userdetails.User(username, user.getPassword(), grantedAuthorityList); return securityUser; } }