Spring安全组件学习
一、SpringSecurity概述
1.1 Spring介绍
Spring Security是为Spring提供的一套声明式安全框架,它提供了一套完整的安全解决方案,能够在web请求级别和方法调用级别进行身份验证与授权; 因为是基于spring框架,所以它充分利用了AOP|DI技术。
Spring security主要解决两个问题
- Web请求级别
- 通过Servlet规范的Filter过滤器,对访问资源进行控制。
- 方法调用级别
- 通过AOP切面技术,对于特定的方法进行权限控制与访问授权。
关键词 | 描述 |
---|---|
认证 | 是为用户建立一个他所声明的主体,主体一般指的是用户、设备或者系统中执行动作的其他系统; |
授权 | 是指用户能否在应用中执行某个操作; |
1.2 Maven依赖
<!--引入security依赖-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.0.1.RELEASE</version>
二、Spring Security快速入门Demo
2.1 导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.atjianyi</groupId>
<artifactId>spring_secruity_demoTest</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>spring_secruity_demoTest Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<spring.version>5.0.2.RELEASE</spring.version>
<spring.security.version>5.0.1.RELEASE</spring.security.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>spring_secruity_demoTest</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.2 配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>SpringSecurity314</display-name>
<!--初始化xml文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置过滤器 过滤器名称不能改变 -->
<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>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
2.3 核心配置文件
form-login中的属性 | 描述 |
---|---|
login-page | 自定义登陆页面的位置 |
login-processing-url | 访问的URL |
username-parameter | 用户名表单参数绑定 |
password-parameter | 密码表单参数绑定 |
authentication-failure-url | 权限校验失败后的登陆地址 |
authentication-success-forward-url | 登陆成功并且权限校验通过 |
default-target-url | 只需要登陆成功,就跳转到URL(权限可能不通过403状态) |
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!-- 配置不控制的资源 -->
<security:http security="none" pattern="/login.html"/>
<security:http security="none" pattern="/error.html"/>
<security:http auto-config="true" use-expressions="false">
<!-- 配置需要认证的资源连接和角色 -->
<security:intercept-url pattern="/**" access="ROLE_USER" />
<!-- 自定义登陆页面
-->
<security:form-login
login-page="/login.html"
login-processing-url="/login"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/error.html"
default-target-url="/succeed.html"
authentication-success-forward-url="/succeed.html"
/>
<!-- 关闭跨域登陆支持 -->
<security:csrf disabled="true"/>
</security:http>
<!-- 在内存当中配置用户角色 -->
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="user" password="{noop}user"
authorities="ROLE_USER" />
<security:user name="admin" password="{noop}admin"
authorities="ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
三、Spring Security使用数据库认证
3.1 传统的登陆操作
3.2 使用SpringSecurity认证操作
3.2.1 数据库认证
在spring security当中要想想使用数据库认证操作,有很多种操作,这里我们及那个使用userDetails完成
- UserDetail源码
- userDetails是一个接口,我们在使用的时候,需要将他实现,现在我们可以理解为,它的作用封装当前用户认证信息的类! 当然,我们也可以使用spring security为我们提供实现user类;
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}
- User类的源码
public class User implements UserDetails, CredentialsContainer {
private String password;
private final String username;
private final Set<GrantedAuthority> authorities;//角色权限组
private final boolean accountNonExpired; //帐户是否过期
private final boolean accountNonLocked; //帐户是否锁定
private final boolean credentialsNonExpired; //认证是否过期
private final boolean enabled; //帐户是否可用
}
- userDetailsService
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
在之前Spring security实现用户登陆流程我们讲过,我们的用户业务逻辑层需要实现此接口,并重写对应的方法。
3.2.2 应用实例
- 导入对应依赖,详见1.2(在5.2.0以上版本可能于tomcat7不兼容)
- 配置过滤器
- 在于Spring整合时候,只需要同时加载springsecurity的配置文件就可以了。
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml classpath:spring/spring-sercurty-confing.xml</param-value>
</context-param>
- 编写配置文件(配置指定Service)
<!--省略约束,和不需要拦截的资源->...
<!--
配置具体的规则
auto-config="true" 不用自己编写登录的页面,框架提供默认登录页面
use-expressions="false" 是否使用SPEL表达式(没学习过)
-->
<security:http auto-config="true" use-expressions="false">
<!-- 配置具体的拦截的规则 pattern="请求路径的规则" access="访问系统的人,必须有ROLE_USER 的角色" -->
<security:intercept-url pattern="/**" access="ROLE_USER,ROLE_ADMIN"/>
<!-- 定义跳转的具体的页面 -->
<security:form-login
login-page="/login.jsp"
login-processing-url="/login.do"
default-target-url="/index.jsp"
authentication-failure-url="/failer.jsp"
authentication-success-forward-url="/pages/main.jsp"
/>
<!-- 关闭跨域请求 -->
<security:csrf disabled="true"/>
<!-- 退出 -->
<security:logout
invalidate-session="true"
logout-url="/logout.do"
logout-success-url="/login.jsp" />
</security:http>
<!-- 切换成数据库中的用户名和密码 -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
<!-- 配置加密的方式-->
<!-- <security:password-encoder ref="passwordEncoder"/>-->
</security:authentication-provider>
</security:authentication-manager>
<!-- 配置加密类 -->
<!-- <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>-->
</beans>
如果不配置加密方式,那么在转换UserDateails时候,在密码前面加上{noop}
- 编写Service继承UserDatealisService
//此处UserService就是上面配置文件配置的提供器。
@Service("userService")
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserInfo userInfo = null;
try {
//根据表单传过来的名称,查询数据空中的用户。
userInfo = userMapper.findUserByName(username);
System.out.println(userInfo);
} catch (Exception e) {
e.printStackTrace();
}
//将查询的对象放入到UserDatelias的实现
User user = new User(userInfo.getUserName(),"{noop}"+userInfo.getUserPwd(),getAuthority(userInfo.getRoleList()));
return user;
}
public List<SimpleGrantedAuthority> getAuthority(List<Role> roleList){
//将角色组放入到集合当中返回
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roleList) {
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName()));
}
return authorities;
}
四、用户密码加密和加密验证登陆
4.1 密码加密
- BCryptPasswordEncoder
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//生成加密后字符串
String encode = bCryptPasswordEncoder.encode(password);
4.2 配置解密
<!-- 切换成数据库中的用户名和密码 -->
<security:authentication-manager>
<security:authentication-provider user-service-ref="userService">
<!-- 告诉其密码的加密方式 -->
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<!-- 配置加密类 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
注意事项:
- tomcat于SpringSecurity
- 再SpringSecurity5.2.0以上版本可能不支持tomcat7
- 安全验证时候,表单提交乱码问题
在web.xml配置文件中将springSecurityFilterChain拦截器放在了
characterEncodingFilter前面,导致会先加载springSecurityFilterChain拦截器
再加载characterEncodingFilter拦截器,而加载springSecurityFilterChain拦截器
时会自动加载CsrfFilter拦截器,这个拦截器会给所有的请求增加一个名为CSRF Token的请求头,这个请求头会将编码设定为iso-8859-1且无法修改,故而characterEncodingFilter
就失去了它原本的作用。