Spring Security介绍: 1.什么是Spring Security? Spring Security是Spring提供的安全认证服务的框架。使用Spring Security可以帮助我们来简化认证和授权的过程。 SpringSecurity内部封装了Filter(只需要在==web.xml容器==中配置一个过滤器--代理过滤器,真实的过滤器在==spring的容器==中配置) 2.Spring Security的使用: 1.maven坐标: <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>5.0.5.RELEASE</version> </dependency> 2.spring security入门 需求:登录才能访问某些页面 1.创建一个工程,导入依赖(此处为了方便导入事先准备好的interface依赖,里面包含了spring和spring security的相关依赖) <?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.it</groupId> <artifactId>spring security</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.itheima</groupId> <artifactId>health_interface</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <!-- 指定端口 --> <port>85</port> <!-- 请求路径 --> <path>/</path> </configuration> </plugin> </plugins> </build> </project> 2.配置web.xml和spring security.xml 1.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_3_0.xsd" id="WebApp_ID" version="3.0"> <!--springmvc的核心控制器,通过启动web容器,加载spring容器--> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-security.xml</param-value> </init-param> <!--第一个启动--> <load-on-startup>1</load-on-startup> </servlet> <!--以.do结尾的url,执行springmvc的控制器--> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!--使用SpringSecurity,创建一个开启SpringSecurity的代理过滤器 注意1:它不是真正的过滤器,真正的过滤器(aop思想),在spring容器中定义 注意2:代理过滤器的名称,一定要叫做springSecurityFilterChain,否则就会抛出异常 org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'DelegatingFilterProxy' available --> <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> </web-app> 2.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:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" 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/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!--springSecurity的配置--> <!--1:定义哪些连接可以放行 security:http pattern="/a.html" :定义访问的url security="none":不需要任何权限,放行 --> <!--<security:http pattern="/a.html" security="none"></security:http>--> <security:http pattern="/css/**" security="none"></security:http> <security:http pattern="/js/**" security="none"></security:http> <!--放行登录的页面--> <security:http pattern="login.html" security="none"></security:http> <!--2:定义哪些连接不可以放行,需要具有Xxx角色,或者具有Xxx权限才可以放行 security:http auto-config="true":自动配置,true:表示可以使用SpringSecurity内置的登录页面完成登录认证,包括登录、退出等功能实现 false:表示需要使用自己定义的登录页面完成登录认证 use-expressions="true":是否使用表达式,true使用表达式(在security:intercept-url中的access=""属性去使用表达式) security:intercept-url pattern="/**":访问的url,/**表示所有的url连接(包括页面、js、css),必须具有角色和权限才能访问 access="":定义访问的角色和权限, access="ROLE_ADMIN":不是不使用表达式,即use-expressions="false" access="hasRole('ROLE_ADMIN'):使用表达式,即use-expressions="true" 即具有ROLE_ADMIN的角色,就可以访问/**定义的所有连接 hasRole:具有...角色 hasAuthority:具有...权限 --> <security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"></security:intercept-url> <!--指定自己的登录页面,作为项目的登录页面,加入表单登录信息的配置 login-page="":指定登录页面 username-parameter="":表单页面定义的用户名属性 password-parameter="":表单页面定义的密码属性 login-processing-url="":表示登录表单处理的URL default-target-url="":如果登录成功,跳转到哪个页面(哪个URL) authentication-failure-url="":如果登录失败(用户名错误、密码错误),跳转到哪个页面(哪个URL) always-use-default-target="":始终使用默认的成功页面作为首页 --> <security:form-login login-page="/login.html" username-parameter="username" password-parameter="password" login-processing-url="/login.do" default-target-url="/index.html" authentication-failure-url="/login.html" always-use-default-target="true"></security:form-login> <!--退出系统 logout-url="/logout.do":退出执行的url路径 logout-success-url="/login.html":退出成功的页面 invalidate-session="true":清空当前用户在服务器上的Session --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"></security:logout> <!--关闭盗链请求csrf--> <security:csrf disabled="true"></security:csrf> </security:http> <!--3:认证管理,(1)将用户名和密码、包括当前用户具有的角色和权限存放到spring-security.xml配置(入门); (2)将用户名和密码、包括当前用户具有的角色和权限从数据库查询(进阶)--> <!--定义认证管理器--> <security:authentication-manager> <!--定义认证供应商--> <security:authentication-provider> <!--定义用户服务,指定用户名和密码--> <security:user-service> <!--security:user name="":指定当前用户名(登录名) password="":指定当前用户名对应的密码 password="{noop}123":表示不使用加密机制,采用明文 authorities="":指定当前用户名具有的角色 数据库中存放的数据,就是admin123ROLE_ADMIN --> <security:user name="admin" password="{noop}123" authorities="ROLE_ADMIN"></security:user> </security:user-service> </security:authentication-provider> </security:authentication-manager> </beans> 3.登录校验: package com.itheima.health.security; import com.alibaba.dubbo.config.annotation.Reference; import com.itheima.health.pojo.Permission; import com.itheima.health.pojo.Role; import com.itheima.health.service.UserService; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; /** * ToDo * * @author Lyle * @date 2020/2/26 */ @Component//相当于注册了SpringSecurityUserService.相当于spring的配置文件中定义<bean id="springSecurityUserService" class="com.itheima.health.security.SpringSecurityUserService"> public class SpringSecurityUserService implements UserDetailsService { @Reference UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("进行登录校验"); // 1:使用用户名作为查询条件,查询用户信息(从数据库查询,此时User既有用户信息,也有角色的集合,同时也有权限的集合) com.itheima.health.pojo.User user = userService.findUserByUsername(username); // 此时说明用户名输入有误,返回null,如果UserDetails对象为null,抛出异常,回退到登录页面,表示登录名输入有误,org.springframework.security.authentication.InternalAuthenticationServiceException: UserDetailsService returned null if(user==null){ return null; } String password = user.getPassword(); // 2:对当前用户分配角色和权限 List<GrantedAuthority> authorities = new ArrayList<>(); if(user.getRoles()!=null && user.getRoles().size()>0){ for (Role role : user.getRoles()) { authorities.add(new SimpleGrantedAuthority(role.getKeyword())); // 添加角色 if(role.getPermissions()!=null && role.getPermissions().size()>0){ for (Permission permission : role.getPermissions()) { authorities.add(new SimpleGrantedAuthority(permission.getKeyword())); // 添加权限 } } } } // 3:组织封装UserDetails对象 /** * User(String username, String password, Collection<? extends GrantedAuthority> authorities) * 其中参数2:表示从数据库查询的密码,对于SpringSecurity来说,自动使用该密码password和表单页面传递的密码进行比对 * 如果一致,跳转到登录成功页面index.html;如果不一致,抛出异常,回退到登录页面login.html * * org.springframework.security.authentication.BadCredentialsException: Bad credentials */ return new User(username,password,authorities); } } 4.在方法上使用注解即可: @PreAuthorize(value = "hasAuthority('CHECKITEM_ADD')") @PreAuthorize(value = "hasAuthority('CHECKITEM_QUERY')")