SpringSecurity安全框架快速入门及进阶
1. 快速入门小demo
1.1 创建maven的web项目(过程略)
1.2 引入springsecurity的框架依赖
<?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.itheima</groupId>
<artifactId>spring-security-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<spring.version>5.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 指定端口 -->
<port>9090</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
1.3 在webapp/WEB-INF文件夹下创建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">
<!--指定spring配置文件,加载sprinsecurity配置文件-->
<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>
<!--作用:进行拦截,让整个web程序的资源都进入过滤器中,从而被springsecurity控制-->
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
1.4 在resources文件夹下建立spring-security.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
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">
<!-- 页面拦截规则 -->
<http>
<!--
pattern:页面的匹配规则
/*:当前文件夹
/**:当前文件夹,包括子文件夹
access: hasRole('Role_Admin')
所有资源必须有ROLE_ADMIN角色才可以访问
-->
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
<!--当前的工程实现表单登录-->
<form-login/>
<!--
退出的登录功能实现,自动添加该功能
默认/logout post
-->
<logout/>
</http>
<!-- 认证管理器 -->
<authentication-manager>
<authentication-provider>
<user-service>
<!--
noop:明文保存的密码
加密:
spring security官方推荐使用更加安全的bcrypt加密方式
spring security 5支持的加密方式有
bcrypt、ldap、MD4、MD5、noop、pbkdf2、scrypt、SHA-1、SHA-256、sha256。
建议采用的是bcrypt加密策略
-->
<user name="admin" password="{noop}123456"
authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
上面的案例为{noop}密码明文方式的代码,我们还有另一种bcrypt加密配置方式,来指定策略,同时,也可以将noop的位置 — bcrypt
<!--认证管理器-->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin"
password="$2a$10$EPtdfwSJ0ABj5JsCyLqhFe1g503DgA4lQvOxyZF/3usoyje5/q/Dy"
authorities="ROLE_ADMIN"></user>
</user-service>
<password-encoder ref="bcryptEncoder"></password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
1.5 在webapp文件夹下创建index.html进行拦截测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>spring-security demo</title>
</head>
<body>
欢迎来到神奇的spring security世界!
</body>
</html>
1.6 打开浏览器,进行测试
1.7 最终目录结构
2. 实际生产环境中,springsecurity整合配置
2.1 创建自己指定的login页面,取代springsecurity自动生成的登录页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/login" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
</table>
<button>登录</button>
</form>
</body>
</html>
2.2 创建login-error页面,用户登录失败后的跳转页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>log-error</title>
</head>
<body>
用户名或密码错误!
</body>
</html>
2.3 修改spirng-security.xml文件
主要修改配置:
- :
login-page:指定指定的登录页面
default-target-url:登录后默认进入的页面
authentication-failure-url:用户名密码错误后跳转的页面1. - 解决spring-security – 关闭csrf验证,跨站请求伪造 token:
使用条件:当我们自己指定登录页面,并且该登录页面为xx.html时需将csrf进行关闭
当使用系统自定义的时,其表单中携带token验证码,所以不需进行csrf关闭操作
<csrf disabled="true"></csrf>
- 由于设定pattern="/**", 所以会对我们指定的login-page/default-target-url/authentication-failure-url进行页面拦截的排除过滤:
<http pattern="/login.html" security="none"></http>
<http pattern="/log_error.html" security="none"></http>
修改后spring-security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
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">
<!--排除springsecurity对登录页面的拦截-->
<http pattern="/login.html" security="none"></http>
<http pattern="/log_error.html" security="none"></http>
<!-- 页面拦截规则 -->
<http>
<!--
pattern:页面的匹配规则
/*:当前文件夹
/**:当前文件夹,包括子文件夹
access: hasRole('Role_Admin')
所有资源必须有ROLE_ADMIN角色才可以访问
-->
<intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
<!--当前的工程实现表单登录-->
<!--
注意点:springsecurity中必须对页面加/,使其为绝对路径,不然会造成无法访问
login-page:指定指定的登录页面
default-target-url:登录后默认进入的页面
authentication-failure-url:用户名密码错误后跳转的页面
-->
<form-login login-page="/login.html" default-target-url="/index.html" authentication-failure-url="/log_error.html" />
<!--退出的登录功能实现,自动添加该功能-->
<logout/>
<csrf disabled="true"></csrf>
</http>
<!--认证管理器-->
<authentication-manager>
<authentication-provider>
<user-service>
<user name="admin"
password="$2a$10$EPtdfwSJ0ABj5JsCyLqhFe1g503DgA4lQvOxyZF/3usoyje5/q/Dy"
authorities="ROLE_ADMIN"></user>
</user-service>
<password-encoder ref="bcryptEncoder"></password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
</beans:beans>
2.4 测试
- 输入localhost:9090后,我们会发现进入了自己刚才自定义的登录页面
- 输入错误的登录名,密码
3. 输入正确的登录名,密码
2.5 最终目录结构
3. 实际生产环境中,springsecurity整合配置2
3.1 实际生产环境中都是从数据库中进行数据的读取,如何解决?
替换xml配置
<user-service>
<user name="admin"
password="$2a$10$EPtdfwSJ0ABj5JsCyLqhFe1g503DgA4lQvOxyZF/3usoyje5/q/Dy"
authorities="ROLE_ADMIN"></user>
</user-service>
替换为:可进行更加灵活的进行用户的权限认证&权限赋予操作(如:后续进行数据库的查询认证以及权限授予),由于查询数据需要进行MyBatis及spring的配置,故在此略
**
* UserDetailService封装了:
* 1.权限认证
* 2.权限赋予
*/
public class UserDetailServiceImpl implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//实际项目中应该从数据库中提取用户列表
List<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
//写死的权限授予,直接授予该用户ROLE_ADMIN权限
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new User(username,"$10$61ogZY7EXsMDWeVGQpDq3OBF1.phaUu7.xrwLyWFTOu8woE08zMIW",grantedAuthorities );
}
}
同时修改spring-security.xml配置
<!--认证管理器-->
<authentication-manager>
<!--
user-service-ref:导入类引用
-->
<authentication-provider user-service-ref="userDetailService">
<!--配置密码加密策略-->
<password-encoder ref="bcryptEncoder"></password-encoder>
</authentication-provider>
</authentication-manager>
<!--向spring容器中,注入bean-->
<beans:bean id="userDetailService" class="com.springsecurity.demo.UserDetailServiceImpl"></beans:bean>
<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
3.2 测试后,验证无误
出现了控制台输入乱码:解决方案,settings – build – build tools – maven – runner 补充添加:-Dfile.encoding=GB2312
从图片中可以看出,再次测试后乱码问题得到解决
3.4 完成数据库密码查询(模板)
public class UserDetailServiceImpl implements UserDetailsService {
@Reference
private AdminService adminService;
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
System.out.println("经过了UserDetailServiceImpl");
//1. 权限认证
Map map=new HashMap<>();
map.put("loginName",s);
map.put("status","1");
List<Admin> list = adminService.findList(map);
if(list.size()==0){
return null;
}
//2.权限赋予
//实际项目中应该从数据库中提取用户的角色列表 通过角色 通过权限
List<GrantedAuthority> grantedAuthorities=new ArrayList<GrantedAuthority>();
//
grantedAuthorities.add( new SimpleGrantedAuthority("ROLE_ADMIN"));
return new User(s,list.get(0).getPassword(),grantedAuthorities);
}
}
最后补充:
SpringSecurity有个同源策略问题:
可以在spring-security.xml中标签体中配置
<!--同源策略-->
<headers>
<frame-options policy="SAMEORIGIN"></frame-options>
</headers>