Spring Security安全框架
简介
-
Spring Security是 Spring提供的安全认证服务的框架(功能强大的权限管理框架)。 使用Spring Security可以帮助我们来简化认证和授权的过程。官网:https://spring.io/projects/spring-security
-
认证:系统提供的用于识别用户r身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认证的目的是让系统知道你是谁
-
授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能。
-
常用的权限框架除了Spring Security,还有Apache的shiro框架。
-
RBAC:Role-Based Access Control,基于角色的访问权限控制
-
功能:登录/认证/鉴权/登出
Spring Security环境搭建
-
pom.xml文件导入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>
-
web.xml文件主要配置SpringMVC的DispatcherServlet和用于整合第三方框架的DelegatingFilterProxy,用于整合Spring Security。 配置哪些请求需要让SpringSecurity来进行认证或鉴权自动管理
<!--委派过滤器,用于整合其他框架--> <filter> <!-- DelegatingFilterProxy用于整合第三方框架 整合spring security时,此过滤器的名称固定springSecurityFilterChain 否则会抛出NoSuchBeanDefinitionException异常 --> <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>
-
在spring-security.xml中主要配置Spring Security的拦截规则和认证管理器
<?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"> <!--配置哪些资源匿名可以访问(不登录也可以访问)--> <!--<security:http security="none" pattern="/pages/a.html"></security:http> <security:http security="none" pattern="/pages/b.html"></security:http>--> <!--<security:http security="none" pattern="/pages/**"></security:http>--> <security:http security="none" pattern="/login.html"></security:http> <security:http security="none" pattern="/css/**"></security:http> <security:http security="none" pattern="/img/**"></security:http> <security:http security="none" pattern="/js/**"></security:http> <security:http security="none" pattern="/plugins/**"></security:http> <!-- auto-config:自动配置,如果设置为true,表示自动应用一些默认配置,比如框架会提供一个默认的登录页面 use-expressions:是否使用spring security提供的表达式来描述权限 --> <security:http auto-config="true" use-expressions="true"> <security:headers> <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问--> <security:frame-options policy="SAMEORIGIN"></security:frame-options> </security:headers> <!--配置拦截规则,/** 表示拦截所有请求--> <!-- pattern:描述拦截规则 pattern:对哪些url进行权限控制 asscess:指定所需的访问角色或者访问权限 isAuthenticated(),登录即可访问 hasAuthority('add'),需要有add权限,才可访问 hasRole('admin'),需要有admin角色,才可访问 --> <!--只要认证通过就可以访问--> <security:intercept-url pattern="/pages/*" access="isAuthenticated()" /> <!-- 如果我们要使用自己指定的页面作为登录页面,必须配置登录表单.页面提交的登录表单请求是由框架负责处理 form-login:定义表单登录信息L login-page:指定登录页面访问URL default-target-url:登录成功后跳转的网页 authentication-failure-url:访问网页权限不够时,跳转的网页 --> <security:form-login login-page="/login.html" username-parameter="username" password-parameter="password" login-processing-url="/login.do" default-target-url="/pages/main.html" authentication-failure-url="/login.html"> </security:form-login> <!-- csrf:对应CsrfFilter过滤器 disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403) --> <security:csrf disabled="true"></security:csrf> <!-- logout:退出登录 logout-url:退出登录操作对应的请求路径 logout-success-url:退出登录后的跳转页面 invalidate-session:true销毁session --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/> </security:http> <!--配置认证管理器--> <security:authentication-manager> <!--配置认证提供者--> <security:authentication-provider user-service-ref="springSecurityUserService"> <!-- user:定义用户信息,可以指定用户名、密码、角色,后期可以改为从数据库查询用户信息 {noop}:表示当前使用的密码为明文 <security:user-service> <security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"/> </security:user-service> --> <!--指定密码加密策略--> <security:password-encoder ref="passwordEncoder"></security:password-encoder> </security:authentication-provider> </security:authentication-manager> <!--配置密码加密对象--> <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> <!--配置SpringSecurityUserService对象,通过@Component注解配置了,这里不用写该对象的bean--> <!--<bean id="springSecurityUserService" class="com.itheima.service.SpringSecurityUserService"/>--> <!--开启spring注解使用,在springmvc.xml配置,使用import导入springmvc.xml中--> <!--<context:annotation-config></context:annotation-config>--> <!--<mvc:annotation-driven></mvc:annotation-driven>--> <!--<context:component-scan base-package="com.it.controller"></context:component-scan>--> <!--开启注解方式权限控制--> <security:global-method-security pre-post-annotations="enabled" /> </beans>
-
从数据库动态查询用户信息,必须按照spring security框架的要求提供一个实现UserDetailsService接口的实现类,并按照框架的要求进行配置即可。框架会自动调用实现类中的方法并自动进行密码校验。
import org.springframework.security.core.userdetails.User; @Component("springSecurityUserService") public class SpringSecurityUserService implements UserDetailsService { @Reference//通过dubbo远程调用UserService private UserService userService; public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //远程调用用户服务,根据用户名查询用户信息 com.ith.POJO.User user = userService.findByUsername(username); if(user == null){ return null; } //动态为当前用户授权 List<GrantedAuthority> list = new ArrayList<>(); Set<Role> roles = user.getRoles(); for (Role role : roles) { list.add(new SimpleGrantedAuthority(role.getKeyword())); Set<Permission> permissions = role.getPermissions(); for (Permission permission : permissions) { list.add(new SimpleGrantedAuthority(permission.getKeyword())); } } UserDetails userDetails = new User(username, user.getPassword(), list); return userDetails; } }
-
controller加上注解进行权限控制
import org.springframework.security.core.userdetails.User; @RestController @RequestMapping("/user") public class UserController { @Reference//通过dubbo远程调用UserDao private UserDao userDao; //从上下文中获取当前登录人的信息和权限 @RequestMapping("/getUsername") public Result getUsername(){ //当Spring security完成认证后,会将当前用户信息保存到框架提供的上下文对象 User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if(user != null){ String username = user.getUsername(); return new Result(true, MessageConstant.GET_USERNAME_SUCCESS,username); } return new Result(false, MessageConstant.GET_USERNAME_FAIL); } @PreAuthorize("hasAuthority('DELETE')")//权限校验 @RequestMapping("delete") public Result delete(Integer id) { try { userService.delete(id); } catch (Exception e) { e.printStackTrace(); return new Result(false, MessageConstant.DELETE_USER_FAIL); } return new Result(true, MessageConstant.DELETE_USER_SUCCESS); } }