SpringSecurity方法级别的权限控制 引言 Spring Security是一个能够为基于Spring的企业应用系统提供安全访问控制解决方案的安全框架,它利用Spring IOC、DI和AOP功能,为企业应用系统提供声明式的安全访问控制功能,简化企业系统为了安全控制而编写大量重复代码的工作,Spring Security支持Url级别的权限控制,同样也支持方法级别的权限控制,今天主要介绍Spring Security方法级别的权限控制。 Spring Security方法级别权限控制方式 Spring Security方法级别权限控制主要有以下几种方式: • intercept-methods定义方法权限控制。 • 使用pointcut定义方法权限控制。 • 使用JSR-250注解定义方法权限控制。 • 使用@Secured注解定义方法权限控制。 • 注解使用表达式定义方法权限控制。 项目搭建 要想实现Spring Security方法级别的权限控制,必须先将项目搭建起来。 创建名称为Spring-Security的web项目 在pom.xml文件中引入相关的依赖包。 org.springframework spring-core 4.2.4.RELEASE org.springframework spring-web 4.2.4.RELEASE org.springframework spring-webmvc 4.2.4.RELEASE org.springframework spring-context-support 4.2.4.RELEASE org.springframework.security spring-security-web 4.1.0.RELEASE org.springframework.security spring-security-config 4.1.0.RELEASE org.aspectj aspectjweaver 1.8.7 org.lucee jsr250 1.0.0 其中: • spring-core、spring-web、spring-context-support是spring相关的依赖包。 • spring-webmvc是springmvc的依赖包。 • spring-security-web、spring-security-config是springsecurity相关的依赖包。 • aspectjweaver是aspectj的依赖包,用来实现pointcut方式的权限控制。 • jsr250是JSR-250标准的依赖包,用来实现jsr250注解方式的权限控制。 创建springmvc.xml和spring-security.xml配置文件。 创建springmvc.xml文件,用来扫描controller。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" 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://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 其中: • context:component-scan是扫描controller注解配置。 • mvc:annotation-driven是开启springmvc注解。 创建spring-security.xml文件,用来进行springsecurity权限控制。
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">
authentication-failure-url="/login_error.html"/>
class="com.itheima.demo.user.UserDetailServiceImpl"> 其中: • http:用来设置Url权限过滤规则,其中的security属性用来设置不受权限控制的行为,intercept-url用来设置访问资源所需的权限,form-login用来设置权限不足跳转的页面,这是设置的是我们自己创建的页面,csrf是关于csrf攻击的设置。 • authentication-manager:设置认证管理器,authentication-provider是配置认证提供者,这里我们通过创建的UserDetailServiceImpl来进行实现。 配置web.xml文件 在web.xml文件中加载springmvc.xml文件和spring-security.xml文件,处理springmvc乱码问题,设置springsecurity的拦截器。 contextConfigLocation classpath:spring/spring-security.xml org.springframework.web.context.ContextLoaderListener springSecurityFilterChain org.springframework.web.filter.DelegatingFilterProxy springSecurityFilterChain / * CharacterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter encoding utf-8 forceEncoding true CharacterEncodingFilter / * springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring/springmvc.xml springmvc *.do 创建UserDetailServiceImpl UserDetailServiceImpl用来进行权限认证,这里我们设置权限为ROLE_USER,会直接配置在spring-security.xml文件的authentication-provider中。 public class UserDetailServiceImpl implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("经过认证类:"+username); List authorities=new ArrayList(); authorities.add(new SimpleGrantedAuthority("ROLE_USER")); return new User(username,"123456",authorities); } } 创建UserController、UserService接口和UserServiceImpl接口实现类 创建UserController,调用Service中的操作 @RestController public class UserController { @Autowired private UserService userService; @RequestMapping("/findAll") public void findAll(){ userService.findAll(); } @RequestMapping("/find") public void find(){ userService.find(); } @RequestMapping("/add") public void add(){ userService.add(); } } 创建UserService接口 public interface UserService { public void findAll(); public void find(); public void add(); } 创建UserServiceImpl实现UserService接口,实现具体的操作 public class UserServiceImpl implements UserService { @Override public void findAll() { for (int i = 0; i < 5; i++) { System.out.println("商品"+i); } } @Override public void find() { System.out.println("商品"); } @Override public void add() { System.out.println("添加商品"); } } 配置权限控制所需的index.html、login.html页面 index.html 登录成功 login.html
运行测试 启动项目 浏览器输入地址"http://localhost:8082/index.html"会出现如下效果 : 说明权限控制已经开始起作用了,接下来就可以进行方法级别的权限控制了。
SpringSecurity方法级别权限控制 intercept-methods方式权限控制 在spring-security.xml文件中配置: 其中: • intercept-methods:需要定义在bean元素下,定义对当前的bean的某些方法进行权限控制。 • protect:配置访问方法所需的权限,需要指定两个属性,access和method,method表示需要拦截的方法名称,可以使用通配符,access表示执行对应的方法需要拥有的权限,多个权限之间可以使用逗号分隔。 运行测试 运行测试,当登录成功之后: 在浏览器输入"http://localhost:8082/find.do",在开发工具的打印台会打印出 如下结果: 在浏览器输入"http://localhost:8082/findAll.do",在开发工具的打印台会打印出如下结果 : 在浏览器输入"http://localhost:8082/add.do",会发现如下结果: 根据结果会发现当通过find.do或者是findAll.do进行请求时,因为在spring-security.xml文件配置了访问find*方法的访问权限是ROLEUSER,所以会直接通过controller调用service的方法来完成请求,但是当通过add.do进行请求时,因为在spring-security.xml文件配置了add方法的访问权限是ROLEADMIN,权限不对,所以会提示访问拒绝。 pointcut方式权限控制 使用pointcut方式进行权限控制,需要先引入aspectjweaver依赖包,同时需要在spring-security.xml文件中配置:
class="com.itheima.demo.service.UserServiceImpl" />
expression="execution(* com.itheima.demo.service.UserServiceImpl.find*())" access="ROLE_USER"/>
expression="execution(* com.itheima.demo.service.UserServiceImpl.add(..))" access="ROLE_ADMIN"/> 其中: • 基于pointcut的方法权限控制是通过global-method-security下的protect-pointcut来定义的。 • protect-pointcut:protect-pointcut中有两个属性,expression和access,可以通过expression设置切点表达式来进行设置拦截的方法,通过access设置访问权限。 运行测试 运行测试,当登录成功之后: 在浏览器输入"http://localhost:8082/find.do",在开发工具的打印台会打印出如下结果: 在浏览器输入"http://localhost:8082/findAll.do",在开发工具的打印台会打印出如下结果: 在浏览器输入"http://localhost:8082/add.do",会发现如下结果: 根据结果会发现当通过find.do或者是findAll.do进行请求时,因为在spring-security.xml中的protect-pointcut中配置了访问find*方法的访问权限是ROLEUSER,所以会直接通过controller调用service的方法来完成请求,但是当通过add.do进行请求时,因为在spring-security.xml中的protect-pointcut配置了add方法的访问权限是ROLEADMIN,权限不对,所以会提示访问拒绝。 使用JSR-250注解方式权限控制 要使用JSR-250注解,首先需要引入jsr250依赖包,同时需要通过设置global-method-security元素的jsr250-annotation="enabled"来启用基于JSR-250注解的支持,默认为disabled,具体配置如下: 另外还需要在对应的java类中进行注解配置: public class UserServiceImpl1 implements UserService { @RolesAllowed("ROLE_USER") @Override public void findAll() { for (int i = 0; i < 5; i++) { System.out.println("商品"+i); } } @DenyAll @Override public void find() { System.out.println("商品"); } @RolesAllowed("ROLE_ADMIN") @Override public void add() { System.out.println("添加商品"); } } 其中: • @RolesAllowed:设置访问对应方法时所应该具有的角色。 • @DenyAll: 表示无论什么角色都不能访问。 运行测试 运行测试,当登录成功之后: 在浏览器输入"http://localhost:8082/find.do",会发现如下结果: 在浏览器输入"http://localhost:8082/findAll.do",在开发工具的打印台会打印出如下结果 : 在浏览器输入"http://localhost:8082/add.do",会发现如下结果: 根据结果会发现当通过findAll.do进行请求时,因为配置了注解 @RolesAllowed("ROLEUSER"),所以会直接通过controller调用service的方法来完成请求,但是通过find.do进行请求时,因为配置了@DenyAll不允许任何人访问,所以会提示访问拒绝,当通过add.do进行请求时,因为配置了@RolesAllowed("ROLEADMIN"),权限不对,所以会提示访问拒绝。 使用@Secured注解方式权限控制 @Secured是由Spring Security定义的用来支持方法权限控制的注解。它的使用也是需要启用对应的支持才会生效的。通过设置global-method-security元素的secured-annotations="enabled"可以启用,具体配置如下: 另外还需要在对应的java类中进行注解配置: public class UserServiceImpl implements UserService { @Secured("ROLE_USER") @Override public void findAll() { for (int i = 0; i < 5; i++) { System.out.println("商品"+i); } } @Secured("ROLE_USER") @Override public void find() { System.out.println("商品"); } @Secured("ROLE_ADMIN") @Override public void add() { System.out.println("添加商品"); } } 其中: • @Secured:设置访问对应方法时所应该具有的角色。 运行测试 运行测试,当登录成功之后: 在浏览器输入"http://localhost:8082/find.do",在开发工具的打印台会打印出如下结果: 在浏览器输入"http://localhost:8082/findAll.do",在开发工具的打印台会打印出如下结果: 在浏览器输入"http://localhost:8082/add.do",会发现如下结果: 根据结果会发现当通过find.do或者是findAll.do进行请求时,因为配置了注解@Secured("ROLEUSER"),所以会直接通过controller调用service的方法来完成请求,但是当通过add.do进行请求时,因为配置的注解是@Secured("ROLEADMIN"),权限不对,所以会提示访问拒绝。 注解使用表达式方式权限控制 Spring Security中也可以使用表达式的注解来进行权限配置,它的使用也是需要在spring-security.xml中启用对应的支持才会生效的,具体配置如下: 另外还需要在对应的java类中进行注解配置: public class UserServiceImpl implements UserService { @PreAuthorize("hasRole('ROLE_USER')") @Override public void findAll() { for (int i = 0; i < 5; i++) { System.out.println("商品"+i); } } @PreAuthorize("hasRole('ROLE_USER')") @Override public void find() { System.out.println("商品"); } @PreAuthorize("hasRole('ROLE_ADMIN')") @Override public void add() { System.out.println("添加商品"); } } 其中: • @PreAuthorize:使用表达式设置访问对应方法时所应该具有的角色。 运行测试 运行测试,当登录成功之后: 在浏览器输入"http://localhost:8082/find.do",在开发工具的打印台会打印出 如下结果: 在浏览器输入"http://localhost:8082/findAll.do",在开发工具的打印台会打印出如下结果: 在浏览器输入"http://localhost:8082/add.do" 会发现如下结果: 根据结果会发现当通过find.do或者是findAll.do进行请求时,因为配置了注解@PreAuthorize("hasRole('ROLEUSER')"),所以会直接通过controller调用service的方法来完成请求,但是当通过add.do进行请求时,因为配置的注解是@PreAuthorize("hasRole('ROLEADMIN')"),权限不对,所以会提示访问拒绝。 总结 方法级别的权限控制是Spring Security的权限控制方式之一,Spring Security可以通过intercept-methods对某个bean下面的方法进行权限控制,也可以通过pointcut对整个Service层的方法进行统一的权限控制,还可以通过注解定义对单独的某一个方法进行权限控制,使用方法级别的权限控制,可以实现细粒度的权限控制,使权限控制更具体细致。
|