`

Spring Security实战(二)-- 方法权限认证

阅读更多

 

前言

 

上次Spring Security实战()-- 基于数据库认证》讲到使用Spring Security如何实现对web层的安全认证,Spring Security还可以实现对方法级别的权限控制。对方法的权限保护主要有两个应用场景:

1、由于开发疏忽导致web层的安全认证有漏洞,从而绕过了web层的安全认证。对重要的方法再进行一次权限控制,可以避免此类安全问题。

2、假设AB两个用户都是普通用户,都有修改和删除自己数据的权限,但不能修改和删除对方的数据,web层的安全认证只是正对链接规则 很难做到如此细粒度的权限控制,但方法级别的权限认证可以实现该功能。

 

本次总结,首先对Spring Security如何实现方法级别的权限控制进行讲解;然后以一个用户管理页面权限控制为例,讲解如何使用页面权限结合方法验证进行细粒度的权限控制。

 

Spring Security方法权权限认证

 

已经在web层引入了Spring Security的情况下,要在方法上使用权限控制很简单,在上一篇demo xml配置文件中,添加相应配置启动“注解保护方法”即可,Spring Security支持三种不同的安全注解:

1Spring Security自带的@Secured

2JSR-250@RolesAllowed

34个表达式驱动注解:@PreAuthorize@PostAuthorize@PreFilter@PostFilter

 

@Secured@RolesAllowed

 

其中@Secured@RolesAllowed注解的作用相同,主要实现根据用户的角色权限判断是否有权限方法该方法,只是一个是SpringSecurity自己的规范,一个是java标准规范。

@Secured的使用

由于@Secured@RolesAllowed注解的作用相同,这里以启用@Secured注解进行讲解,要启用@Secured注解可以在xml配置文件中添加如下配置:

<!--<security:global-method-security jsr250-annotations="enabled"/>-->
<security:global-method-security secured-annotations="enabled"/>

然后在需要做权限控制的方法上添加@Secured注解即可:

    

@Secured({"ROLE_USER","ROLE_ADMIN"})
    public void userPermit() {
        System.out.println("允许普通角色和管理员角色访问");
    }
    @Secured("ROLE_ADMIN")
    public void adminPermit() {
        System.out.println("允许管理员角色访问");
    }

 

@Secured("ROLE_ADMIN")等价于表达式@Secured("hasRole('ROLE_USER')")Spring Security还提供了类似的其他内置表达式:



 

这张来自官网的表很关键,通过上述表达式可以覆盖我们遇到的大部分权限认证场景。其中hasPermission()表达式为扩展表达,用户可以自己实现PermissionEvaluator接口很方便的完成自定义扩展。

 

4个表达式驱动注解

 

@PreAuthorize@PostAuthorize@PreFilter@PostFilter 4个驱动表达式注解使用SpEl表达式,可以是实现更细粒度的表达式约束。其中前两者可以用来在方法调用前或者调用后进行权限检查,后两者可以用来对集合类型的参数或者返回值进行过滤。要使它们的定义能够对我们的方法的调用产生影响我们需要设置global-method-security元素的pre-post-annotations=enabled”,默认为disabled

<!—开启@Secured注解,同时开启4个表达式驱动注解-->
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled"/>
 

 

在需要做权限认证的方法上添加注解:

/**
     * 普通管理员 只能获取自己的店铺列表
     * @param username
     * @return
     */
    @Override
    @PreAuthorize("principal.username.equals(#username)")
    public List<ShopData> select(String username) {
        List<ShopData> ret = new ArrayList<>();
        for(ShopData temp:shops){
            if(temp.getUsername().equals(username)){
                ret.add(temp);
            }
        }
        return ret;
    }
 

 

上述注解,可以隔离不同普通用户之间的数据 彼此不可见。

 

再来看一个稍微复杂点的例子:

@PreAuthorize("hasAnyRole('ROLE_USER','ROLE_ADMIN')")
    @PreFilter("hasRole('ROLE_ADMIN') || filterObject.shopdata.username == principal.username")
    public void deletexx(List<ShopData> list) {
        //省略代码
    }

 

@PreAuthorize("hasAnyRole('ROLE_USER','ROLE_ADMIN')")表示在方法调用前进行权限认证,具备'ROLE_USER','ROLE_ADMIN'角色的用户可以访问该方法。

 

@PreFilter("hasRole('ROLE_ADMIN') || filterObject.shopdata.username == principal.username")含义为:如果是超级管理员可以删除list中的所有数据,如果是普通管理员,需要对list进行过滤 只能删除自己的数据。

 

hasPermission表达式自定义权限

 

有时候通过上述常规表示式无法完成一些复杂的权限认证,比如:根据id删除数据,判断如果是超级管理员可以直接删除,如果是普通管理原型 需要根据id先查询数据,再判断数据创建者是否是当前用户。这时只能通过hasPermission表达式实现,要使用hasPermission表达式必须实现自己的PermissionEvaluator接口:

@Component("myPermissionEvaluator")
public class MyPermissionEvaluator implements PermissionEvaluator {
 
    private static final GrantedAuthority ADMIN = new SimpleGrantedAuthority("ROLE_ADMIN");
 
    @Resource
    private ShopDataHelper shopDataHelper;
 
    @Override
    public boolean hasPermission(Authentication authentication, Object o, Object o1) {
        if(o instanceof Integer){
            //管理员拥有所有权限
            if(isAdmin(authentication)){
                return true;
            }
            Integer id = (Integer) o;
            ShopData shopData = shopDataHelper.selectById(id);
            String username = shopData.getUsername();
 
            //判断普通管理员是否有删除、修改权限
            if("delete".equals(o1) || "update".equals(o1)){
                if(authentication.getName().equals(username)){
                    return true;
                }else{
                    return false;
                }
            }
        }
 
        throw new UnsupportedOperationException("hasPermission 第一个参数必须是Integer型,第二个参数必须为delete或者update");
    }
 
    /**
     * 暂不实现
     */
    @Override
    public boolean hasPermission(Authentication authentication, Serializable serializable, String s, Object o) {
        throw new UnsupportedOperationException();
    }
 
    private boolean isAdmin(Authentication authentication){
        return authentication.getAuthorities().contains(ADMIN);
    }
}

 

 

该接口有两个主要方法:

boolean hasPermission(Authentication authentication, Object targetDomainObject,
                                                                 Object permission);
 
boolean hasPermission(Authentication authentication, Serializable targetId,
                                                                 String targetType, Object permission);

这里MyPermissionEvaluator只实现了第一个方法,在使用hasPermission表达式时,不用传Authentication参数,默认会自动带上:

   @PreAuthorize("hasPermission(#id,'update')")
    public void update(Integer id) {
        for(ShopData temp:shops){
            if(temp.getId()==id){
                if(temp.isState()){
                    temp.setState(false);
                }else{
                    temp.setState(true);
                }
                break;
            }
        }
  }

 

@PreAuthorize("hasPermission(#id,'update')")权限控制为:如果是超级管理员可以直接删除数据,如果是普通管理员首先通过id查询得到该id对应的店铺信息,然后判断该店铺的创建者是否是当前用户,如果是才允许删除操作。这部分逻辑被封装到MyPermissionEvaluator中。

 

有人会说,不使用hasPermission表达式直接在update方法中做这部分校验操作也可以,实际工作中有很多系统也是这样做的。但是采用hasPermission表达式可以把业务逻辑代码与权限控制代码完全隔离,而且复用性更好,其他有类似权限控制的地方直接使用这个hasPermission表达式即可。

 

Demo演示

 

这里笔者根据上述讲解写了一份demo演示代码,github地址为:https://github.com/gantianxing/spring-security1.git。在运行代码之前,首先执行下列sql语句:

-- ----------------------------
-- Table structure for `authorities`
-- ----------------------------
DROP TABLE IF EXISTS `authorities`;
CREATE TABLE `authorities` (
  `username` varchar(50) COLLATE utf8_bin NOT NULL,
  `authority` varchar(50) COLLATE utf8_bin NOT NULL,
  UNIQUE KEY `ix_auth_username` (`username`,`authority`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
 
-- ----------------------------
-- Records of authorities
-- ----------------------------
INSERT INTO `authorities` VALUES ('A', 'ROLE_ADMIN');
INSERT INTO `authorities` VALUES ('A', 'ROLE_USER');
INSERT INTO `authorities` VALUES ('B', 'ROLE_USER');
INSERT INTO `authorities` VALUES ('C', 'ROLE_USER');
 
-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `username` varchar(50) COLLATE utf8_bin NOT NULL,
  `password` varchar(50) COLLATE utf8_bin NOT NULL,
  `enabled` tinyint(1) NOT NULL,
  PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
 
-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('A', '123456', '1');
INSERT INTO `users` VALUES ('B', '123456', '1');
INSERT INTO `users` VALUES ('C', '123456', '1');
 

 

上述sql语句创建了三个用户ABC,其中A用户是超级管理员具备:ROLE_USERROLE_ADMIN角色;BC用户都是普通管理员,只具备ROLE_USER角色。

 

程序启动后,会在内存里初始化3个店铺信息数据(ShopData),创建者分别为ABC。访问登陆页http://localhost/login,首先使用A账号登陆:



 

再访问店铺列表页,由于A账号是超级管理员,可以看到所有的三条数据:




如果切换成B用户登陆,再次访问店铺列表页,只能看到B用户创建的店铺信息:



 

 

访问http://localhost/shop/add,可以在当前用户下创建一个新店铺(再次访问店铺列表页):



 

 

访问http://localhost/shop/update?id=2,可以修改店铺上下线状态,再次访问店铺列表页:



 

 

如果访问http://localhost/shop/update?id=1,由于当前登录用户是B,但id=1的店铺是A用户创建的,所以没有权限,执行结果为:



 

 

 

同理还可以执行http://localhost/shop/delete?id=2,对B用户自己的数据进行删除,但缺无法删除别人的数据,如果是A用户登陆可以修改和删除所有数据。这部分测试内容,不再演示,读者可以自行测试。

 

转载请注明处在:

 

http://moon-walker.iteye.com/blog/2395306

  • 大小: 87.8 KB
  • 大小: 6.3 KB
  • 大小: 9.6 KB
  • 大小: 7 KB
  • 大小: 12.1 KB
  • 大小: 8.1 KB
  • 大小: 7.6 KB
0
0
分享到:
评论

相关推荐

    spring-security-ldap-2.0.1

    1. GroupSearchFilter:Spring Security LDAP提供了GroupSearchFilter,可以在认证成功后搜索用户所属的组信息,实现基于组的角色分配和权限控制。 2. AuthoritiesPopulator:此接口用于将从LDAP获取的用户角色转换...

    SpringSecurity实战代码

    本实战代码将带你深入理解并实际操作SpringSecurity的核心功能,包括用户认证与授权、注销、权限限制、"记住我"功能以及首页定制。 1. 用户认证与授权:在SpringSecurity中,认证过程是识别用户身份,而授权则是...

    Spring Security实战例子

    通过这个Spring Security实战例子,你可以深入了解Spring Security的配置、认证和授权机制,以及如何与数据库集成。实践是最好的老师,动手完成这四个小项目将有助于巩固理解,并为你在实际项目中应用Spring ...

    spring-security-jwt-demo.zip

    《Spring Security与JWT整合实战详解》 在现代Web应用程序中,安全性和用户认证是至关重要的。Spring Security作为Java领域中最受欢迎的安全框架,为开发者提供了强大的安全解决方案。而JSON Web Token(JWT)则是...

    spring-security-2.0.5.jar2

    1. 认证流程:Spring Security的认证过程包括了认证请求、凭证匹配、权限检查等步骤。当用户尝试访问受保护的资源时,Spring Security会启动认证过程,判断用户是否具有合法的身份。 2. 用户详情服务...

    spring-security-web-3 source code

    二、Spring Security架构 Spring Security的架构主要由以下几部分组成: 1. **Filter Chain**:Spring Security通过一系列Filter来处理HTTP请求,每个Filter执行特定的安全任务,如身份验证、会话管理等。 2. **...

    spring-security-3.1.0.RC3

    在实际项目中,Spring Security可以用于保护RESTful API、实现单点登录(SSO)、保护静态资源、控制对Controller方法的访问等。通过配置不同的过滤器、提供自定义访问决策策略,开发者能够精确控制用户的访问权限。 ...

    spring-cloud-security例子

    《Spring Cloud Security实战详解》 在微服务架构中,安全问题尤为重要,而Spring Cloud Security作为Spring Cloud生态的一部分,为开发者提供了强大的安全管理和身份验证功能。本文将深入探讨Spring Cloud ...

    spring-security-3.1.0.RELEASE

    Spring Security是Java平台上广泛使用的安全框架,其3.1.0.RELEASE版本是该框架的一个重要里程碑,为开发者提供了全面的安全控制,从Web应用到企业级服务,涵盖了认证、授权和会话管理等多个层面。本文将深入探讨...

    Spring Security 资料合集

    这三份资料——"实战Spring Security 3.x.pdf"、"Spring Security 3.pdf" 和 "Spring Security使用手册.pdf" 将深入探讨这些概念,并提供实践指导,帮助读者掌握如何在实际项目中应用Spring Security。通过学习这些...

    spring security权限管理开发手册及实例.rar

    - **springsecurity-sample**:这个示例项目可能包含了从创建用户、角色到实现登录、权限控制的完整流程。你可以通过它学习如何配置Spring Security XML或Java配置,如何编写自定义的认证和授权逻辑,以及如何在...

    Spring Security3.2搭建LDAP认证授权

    **二、Spring Security与LDAP集成** 1. **配置LDAP连接**:首先,我们需要在Spring Security的配置类中添加LDAP服务器的连接信息,包括URL、基础DN(Distinguished Name)以及管理员凭证。 2. **定义LDAP认证提供者*...

    spring-security-3.0.5.RELEASE

    2. **授权机制**:通过Access Decision Manager和Access Decision Voter,Spring Security支持细粒度的访问控制,如基于角色的访问控制(RBAC)和基于权限的访问控制(ABAC)。此外,它可以与Spring AOP结合,实现...

    spring-security-sample案例代码

    这个"spring-security-sample"案例代码提供了一个实战教程,帮助开发者理解和应用Spring Security的核心概念。在这个项目中,我们将深入探讨Spring Security的基本配置、认证流程以及授权机制。 首先,Spring ...

    SpringSecurity实现的权限管理(含包)

    7. **实战应用**:对于初学者,可以首先创建一个简单的登录页面,然后配置SpringSecurity来处理登录请求。接着,定义角色和权限,将它们分配给用户。最后,通过注解或配置文件设定哪些URL需要特定角色才能访问。 综...

    狂神spring-security静态资源.zip

    Spring Security 是Spring生态系统中的一个组件,用于提供认证(Authentication)和授权(Authorization)功能。它为Web应用程序提供了全面的安全解决方案,包括登录、权限控制、会话管理、CSRF防护等。 2. **核心...

    Spring Security3 中文版 张卫滨 推荐

    ### 第二章:Spring Security起步 这一章重点介绍了如何快速集成Spring Security到现有的项目中。 - **安全的核心概念**:深入浅出地解释了安全领域的重要概念,如认证、授权等。 - **实现Spring Security的XML...

    简单的springsecurity实战,非常适合springsecurity入门级别的老铁学习,这个小demo采用的.zip

    Spring Security 是一个强大的安全框架,用于为 Java 应用程序提供认证、授权和安全防护功能。这个实战项目针对初学者,旨在帮助理解 Spring Security 的基本概念和配置过程。在这个小型的示例项目中,我们将探讨...

    Spring Security+OAuth2 精讲,打造企业级认证与授权

    本课程"Spring Security+OAuth2 精讲,打造企业级认证与授权"深入浅出地讲解了这两个框架的使用和集成,旨在帮助开发者构建安全、高效的应用系统。 Spring Security是Spring生态系统中的一个强大安全框架,它提供了...

    全套Spring Security入门到项目实战课程

    ### Spring Security 全套入门到项目实战课程知识点详解 #### 一、Spring Security 概述 **1.1 Spring Security 介绍** - **定义**: Spring Security 是一款基于 Spring 框架的身份认证(Authentication)与用户...

Global site tag (gtag.js) - Google Analytics