SpringSecurit
概述:
在web应用开发中,安全无疑是十分重要的,选择Spring Security来保护web应用是一个非常好的选择。Spring Security 是Spring项目之中的一个安全模块,可以非常方便与Spring项目无缝集成。利用 Spring IoC/DI和AOP功能,为系统提供了声明式安全访问控制功能,减少了为系统安全而编写大量重复代码的工作。特别是SpringBoot项目中加入Spring Security更是十分简单。
核心功能:
认证:用户登录,系统授权访问
授权:当前用户有哪些资源可以访问
攻击防护:防止伪造身份
核心就是一组过滤链,项目启动后会将自动配置。最核心的就是Basic Authentication Filter用来认证用户身份,一个soring security中一种过滤器处理一种认证方式。
spring security是spring采用AOP思想,基于servlet过滤器实现的安全框架,它提供了完善的认证机制和方法级别的授权功能。
快速入门
创建web项目
导入spring相关依赖
<dependencies> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.26</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.6.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jsp-api</artifactId> <version>2.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>jsr250-api</artifactId> <version>1.0</version> </dependency> </dependencies>
创建配置文件
spring的:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="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"> </beans>
springmvc的:
<?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 配置扫描路径--> <context:component-scan base-package="com.bruce.controller" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> <mvc:default-servlet-handler/> <mvc:annotation-driven/> </beans>
use-default-filters="true" 的意思是自动扫描@controller @Repository @service 配置为flase就是只扫描指定的类!
web.xml
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!-- 初始化spring容器 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- post乱码过滤器 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 前端控制器 --> <servlet> <servlet-name>dispatcherServletb</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation不是必须的, 如果不配置contextConfigLocation, springmvc的配置文件默认在:WEB-INF/servlet的name+"-servlet.xml" --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServletb</servlet-name> <!-- 拦截所有请求jsp除外 --> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
springsecurity整合
导入config taglibs 依赖
spring-security-core.jar:核心包,任何SpringSecurity功能都需要此包 spring-security-web.jar:web工程必须,包含过滤器和相关的web安全基础结构代码 spring-security-config.jar:用于解析xml配置文件,用到SpringSecurity的xml配置文件的就要用到此包 spring-security-taglibs.jar:SpringSecurity提供的动态标签库,jsp页面可以用
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.1.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>5.1.5.RELEASE</version> </dependency>
在web.xml中配置过滤器
<!-- 配置过滤器链 springSecurityFilterChain名称固定--> <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>
SpringSecurity 配置文件 spring-security.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" 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-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd"> <!-- 设置可以用spring的el表达式配置Spring Security并自动生成对应配置组件(过滤器) auto-config="true" 表示自动加载SpringSecurity的配置文件 use-expressions="true" 使用Spring的EL表达式 --> <security:http auto-config="true" use-expressions="true"> <!-- 拦截资源 pattern="/**" 拦截所有的资源 access="hasAnyRole('role1')" 表示只有role1这个角色可以访问资源 --> <!--使用spring的el表达式来指定项目所有资源访问都必须有ROLE_USER或ROLE_ADMIN角色--> <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"></security:intercept-url> </security:http> <!-- 设置置Spring Security认证用户来源 noop:SpringSecurity中默认 密码验证是要加密的 noop表示不加密 --> <security:authentication-manager> <security:authentication-provider> <security:user-service> <security:user name="shuaige" password="{noop}123" authorities="ROLE_USER"></security:user> <security:user name="lianzgai" password="{noop}123" authorities="ROLE_ADMIN"></security:user> </security:user-service> </security:authentication-provider> </security:authentication-manager> </beans>
导入springsecurity配置文件
将spring-security.xml配置到applicationContext.xml中
springsecurity的配置文件需要加载到spring容器中,所以可以通过import来导入
<import resource="classpath:spring-security.xml"></import>
注意:如果想要自己的自定义页面,要从这里这个<input name="_csrf" type="hidden" value="b90a7914-cbbd-4dc5-9bfe-0695ef9fc5b1" />入手。
现在就需要进行验证才能进入Hello World了。
如何将这个登录界面换成我们需要的呢?
准备好一个自己的 login , 首页home,失败fail页面!
配置认证信息:
<!--指定login.jsp页面可以被匿名访问 --> <security:intercept-url pattern="/login.jsp" access="permitAll()"/>
<!-- 拦截资源 pattern="/**" 拦截所有的资源 access="hasAnyRole('role1')" 表示只有role1这个角色可以访问资源 --> <!--使用spring的el表达式来指定项目所有资源访问都必须有ROLE_USER或ROLE_ADMIN角色--> <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')"></security:intercept-url> <!--指定自定义的认证页面--> <security:form-login login-page="/login.jsp" login-processing-url="/login" authentication-success-forward-url="/home.jsp" authentication-failure-forward-url="/failure.jsp"/> <!--关闭CSRF false 开启--> <security:csrf disabled="true"/> </security:http>
上面的login页面就是登陆进来的页面,当我们的csrf关闭的时候,就可以直接进行登录了,但是时没有任何安全认证。false的时候就是开启!
<form action="/login" method="post"> 账号:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="登录"><br> </form>
注意应该使用post方法。
当我们再次进行登录的时候会爆出403
403什么异常?这是SpringSecurity中的权限不足!这个异常怎么来的?还记得上面SpringSecurity内置认证页面源码中的那个_csrf隐藏input吗?问题就在这了!
我们查看源码:
我们可以看出 GET HEAD TRACE OPTIONS 提交的数据不会csrf验证!
此时我们就明白了,自己的认证页面,请求方法为post,但却没有携带token,所以才会出现403权限不足的情况,我么你只需要在认证页面携带token请求!
<security:csrf disabled="false"/> //开启csrf保护机制
页面导入token
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %> <form action="/login" method="post"> 账号:<input type="text" name="username"><br> 密码:<input type="password" name="password"><br> <input type="submit" value="登录"><br> <security:csrfInput/> </form>
注销也是一样
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %> <html> <head> <title>Title</title> </head> <body> <form method="post" action="/logout"> <h1>home界面</h1> <security:csrfInput/> <input type="submit" value="注销"> </form> </body> </html>
此时我们的登录和注销页面就都很安全啦!!