SpringSecurity实现动态加载权限信息的方法

实现动态加载权限信息的方法是Spring Security中非常重要的一部分,可以根据用户的动态信息进行精确的授权管理。下面是详细的实现攻略。

1. 编写权限信息源的代码

Spring Security中支持自定义的权限信息源,我们需要实现 org.springframework.security.access.vote.RoleVoter 接口并提供动态的用户权限信息。

public class CustomRoleVoter implements RoleVoter {

    private Map<String, List<ConfigAttribute>> roleMap;

    public CustomRoleVoter(Map<String, List<ConfigAttribute>> roleMap) {
        this.roleMap = roleMap;
    }

    @Override
    public boolean supports(ConfigAttribute attribute) {
        return attribute.getAttribute() != null && attribute.getAttribute().startsWith("ROLE_");
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

    @Override
    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
        int result = ACCESS_ABSTAIN;
        Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
        for (ConfigAttribute attribute : attributes) {
            if (this.supports(attribute)) {
                result = ACCESS_DENIED;
                String roleName = attribute.getAttribute();
                List<ConfigAttribute> configs = roleMap.get(roleName);
                if (configs != null && !configs.isEmpty()) {
                    for (ConfigAttribute configAttribute : configs) {
                        if (authorities.contains(configAttribute)) {
                            return ACCESS_GRANTED;
                        }
                    }
                }
            }
        }
        return result;
    }
}

2. 创建SQL数据表

我们将创建一个名为 user_role 的表来存储用户角色的权限信息。

CREATE TABLE `user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `authority` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
);

3. 向表中添加数据

我们需要在表中添加一些测试数据。

INSERT INTO `user_role` (`username`, `authority`) VALUES
('user', 'ROLE_USER'),
('admin', 'ROLE_ADMIN'),
('admin', 'ROLE_USER');

4. 创建数据源

我们需要创建一个数据源,并使用 JdbcDaoImpl 从数据库中动态加载权限信息。

<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" />
    <beans:property name="url" value="jdbc:mysql://localhost:3306/test" />
    <beans:property name="username" value="root" />
    <beans:property name="password" value="password" />
</beans:bean>

<beans:bean id="jdbcDao" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
    <beans:property name="dataSource" ref="dataSource" />
    <beans:property name="usersByUsernameQuery" value="SELECT username,password,enabled FROM users WHERE username=?"/>
    <beans:property name="authoritiesByUsernameQuery" value="SELECT username,authority FROM user_role WHERE username=?"/>
</beans:bean>

5. 配置权限信息汇集点与角色配置

我们需要创建一个表示权限信息汇集点的 SecurityMetadataSource 并提供角色配置信息。

public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

    private Map<String, List<ConfigAttribute>> roleMap;

    public CustomSecurityMetadataSource(Map<String, List<ConfigAttribute>> roleMap) {
        this.roleMap = roleMap;
    }

    @Override
    public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
        FilterInvocation filterInvocation = (FilterInvocation) object;
        HttpServletRequest request = filterInvocation.getHttpRequest();
        String url = request.getRequestURI().substring(request.getContextPath().length());
        List<ConfigAttribute> attributes = roleMap.get(url);
        if (attributes != null && !attributes.isEmpty()) {
            return new HashSet<>(attributes);
        }
        return null;
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> set = new HashSet<>();
        for (List<ConfigAttribute> attrs : roleMap.values()) {
            set.addAll(attrs);
        }
        return set;
    }

    @Override
    public boolean supports(Class<?> clazz) {
        return true;
    }

}

6. 配置访问控制

我们需要创建一个表示访问控制的 AccessDecisionManager 并将 CustomRoleVoterCustomSecurityMetadataSource 与之相互关联。

<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
    <beans:constructor-arg>
        <beans:list>
            <beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
            <beans:bean class="com.example.CustomRoleVoter">
                <beans:constructor-arg>
                    <beans:map>
                        <beans:entry key="/admin">
                            <beans:list>
                                <beans:bean class="org.springframework.security.access.SecurityConfig">
                                    <beans:constructor-arg value="ROLE_ADMIN" />
                                </beans:bean>
                                <beans:bean class="org.springframework.security.access.SecurityConfig">
                                    <beans:constructor-arg value="ROLE_USER" />
                                </beans:bean>
                            </beans:list>
                        </beans:entry>
                        <beans:entry key="/user">
                            <beans:list>
                                <beans:bean class="org.springframework.security.access.SecurityConfig">
                                    <beans:constructor-arg value="ROLE_USER" />
                                </beans:bean>
                            </beans:list>
                        </beans:entry>
                    </beans:map>
                </beans:constructor-arg>
            </beans:bean>
        </beans:list>
    </beans:constructor-arg>
</beans:bean>

<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
    <beans:property name="securityMetadataSource">
        <beans:bean class="com.example.CustomSecurityMetadataSource">
            <beans:constructor-arg>
                <beans:map>
                    <beans:entry key="/admin">
                        <beans:list>
                            <beans:bean class="org.springframework.security.access.SecurityConfig">
                                <beans:constructor-arg value="ROLE_ADMIN" />
                            </beans:bean>
                            <beans:bean class="org.springframework.security.access.SecurityConfig">
                                <beans:constructor-arg value="ROLE_USER" />
                            </beans:bean>
                        </beans:list>
                    </beans:entry>
                    <beans:entry key="/user">
                        <beans:list>
                            <beans:bean class="org.springframework.security.access.SecurityConfig">
                                <beans:constructor-arg value="ROLE_USER" />
                            </beans:bean>
                        </beans:list>
                    </beans:entry>
                </beans:map>
            </beans:constructor-arg>
        </beans:bean>
    </beans:property>
    <beans:property name="accessDecisionManager" ref="accessDecisionManager" />
    <beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>

7. 验证用户身份

最后,我们需要在Web应用程序中配置 springSecurityFilterChain 并向其中添加 FilterSecurityInterceptor

<security:http pattern="/admin/**" auto-config="false" use-expressions="false">
    <security:intercept-url pattern="/admin/**" access="ROLE_ADMIN,ROLE_USER" />
    <security:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" />
</security:http>

<security:http pattern="/user/**" auto-config="false" use-expressions="false">
    <security:intercept-url pattern="/user/**" access="ROLE_USER" />
    <security:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" />
</security:http>

<security:authentication-manager>
    <security:authentication-provider user-service-ref="jdbcDao" />
</security:authentication-manager>

<beans:bean id="springSecurityFilterChain" class="org.springframework.web.filter.DelegatingFilterProxy">
    <beans:property name="targetBeanName" value="filterSecurityInterceptor" />
</beans:bean>

示例1:验证用户访问Admin页面的权限

假设某位用户拥有 ROLE_USERROLE_ADMIN 权限,但是在访问 /admin 页面时被拒绝,因为访问此页面必须要满足 ROLE_ADMIN 权限。

我们可以使用以下方法验证账号和密码。

用户名:admin 密码:123456

示例代码如下:

@Test
public void testAccessAdminPage() throws Exception {
    MvcResult result = mockMvc.perform(get("/admin/hello").with(httpBasic("admin", "123456")))
            .andDo(print())
            .andExpect(status().isOk())
            .andReturn();
    String content = result.getResponse().getContentAsString();
    assertThat(content).isEqualTo("Hello Admin");
}

示例2:验证用户访问User页面的权限

假设某个用户只拥有 ROLE_USER 权限,那么访问 /user 页面将是允许的,但是访问 /admin 页面将被禁止。

我们可以使用以下方法验证账号和密码。

用户名:user 密码:123456

示例代码如下:

@Test
public void testAccessUserPage() throws Exception {
    MvcResult result = mockMvc.perform(get("/user/hello").with(httpBasic("user", "123456")))
            .andDo(print())
            .andExpect(status().isOk())
            .andReturn();
    String content = result.getResponse().getContentAsString();
    assertThat(content).isEqualTo("Hello User");
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity实现动态加载权限信息的方法 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • springmvc4+hibernate4分页查询功能实现

    让我来详细讲解一下“springmvc4+hibernate4分页查询功能实现”的完整攻略。 1. 前言 在开发Web应用过程中,分页查询功能是经常会用到的一项功能。SpringMVC和Hibernate是当前较为流行的Web开发框架,结合起来使用可以实现很好的分页功能。下面,我们将详细说明如何使用SpringMVC和Hibernate实现分页查询功能。 2…

    Java 2023年6月15日
    00
  • Java读取Properties文件的七种方法的总结

    下面我将为你详细讲解Java读取Properties文件的七种方法的总结。 什么是Properties文件 Properties是一个文件格式,用于表示一些配置信息,形如key=value的形式。 例如,在Java的Spring框架中,会使用application.properties文件进行应用程序的一些配置。其中可以包含数据库配置、服务器端口号、系统环境…

    Java 2023年5月19日
    00
  • 几道java循环练习题(适合新人)

    首先,对于这篇“几道java循环练习题(适合新人)”文章,它包含了多个练习题,都是基于Java的循环语法实现的。对于初学者来说,可以通过熟悉这些练习题,掌握Java的循环语法。 下面,我们来逐个解析。 第一道题:九九乘法表 这道题要求我们输出九九乘法表。我们可以使用双重循环来实现,外层循环控制行数,内层循环控制列数。 for (int i = 1; i &l…

    Java 2023年5月24日
    00
  • 从0开始学习大数据之java spark编程入门与项目实践

    从0开始学习大数据之Java Spark编程入门与项目实践攻略 前言 在大数据时代,数据量和数据处理的复杂性不断增加,需要更加高效和灵活的处理方式。Apache Spark作为当前最流行的大数据处理框架之一,优化了Hadoop MapReduce的不足,支持复杂的数据处理,具有高效、可扩展、易用、友好的API等特点,因此成为很多企业和个人的选择。本文将详细介…

    Java 2023年5月19日
    00
  • 一天吃透操作系统八股文

    操作系统的四个特性? 并发:同一段时间内多个程序执行(与并行区分,并行指的是同一时刻有多个事件,多处理器系统可以使程序并行执行) 共享:系统中的资源可以被内存中多个并发执行的进线程共同使用 虚拟:通过分时复用(如分时系统)以及空分复用(如虚拟内存)技术把一个物理实体虚拟为多个 异步:系统进程用一种走走停停的方式执行,(并不是一下子走完),进程什么时候以怎样的…

    Java 2023年4月17日
    00
  • 从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate

    下面我将详细讲解“从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate”的完整攻略。 前置要求 在正式进行搭建之前,需要确保你已经安装配置好以下软件: JDK Maven Tomcat IDE(推荐使用IntelliJ IDEA) 步骤一:创建Maven项目 首先,我们需要创建一个Maven项目。在IDE中,找到创建M…

    Java 2023年5月20日
    00
  • 解决struts2 拦截器修改request的parameters参数失败的问题

    首先,我们需要了解为什么拦截器无法修改参数。这是因为Struts 2在请求参数提交后,将参数作为只读值放到了ValueStack中,而拦截器只能获取到ValueStack中原有的参数值,而不能修改ValueStack中的参数。 要解决这个问题,我们需要使用Struts2提供的params拦截器。这个拦截器会在Action执行之前拦截请求,并将请求参数转换为可…

    Java 2023年5月20日
    00
  • vue cli3.0结合echarts3.0与地图的使用方法示例

    下面是关于“vue cli 3.0结合echarts 3.0与地图的使用方法示例”的完整攻略。 步骤一:创建基于vue-cli3.0的工程 Vue CLI是一个基于vue.js的全新工具,用于快速构建vue.js项目,它提供了:node命令行交互工具、快速原型开发、自动代码规范检测、构建和部署功能等。 详细步骤: 确保你已经安装了Node.js,命令行输入n…

    Java 2023年6月15日
    00
合作推广
合作推广
分享本页
返回顶部