目录
    • 1、securitymetadatasource
    • 2、userdetailsservice
    • 3、accessdecisionmanager
    • 1 使用idea的srping initializr 创建一个项目 我的版本如下pom.xml
    • 2,创建一个springsecurity配置类,你也可以使用配置文件的方法。我这里使用了boot的配置类
    • 3、自定义securitymetadatasource拦截器

后续会讲解如何实现方法拦截。其实与url拦截大同小异。

拦截方法,会更简单一点吧 基于permissionevaluator 可以自行先了解

1、了解主要的过滤器

1、securitymetadatasource

权限资源拦截器。

有一个接口继承与它filterinvocationsecuritymetadatasource,但filterinvocationsecuritymetadatasource只是一个标识接口,
 对应于filterinvocation,本身并无任何内容:

主要方法:

    public collection<configattribute> getattributes(object object) throws illegalargumentexception {
     
    }

每一次请求url,都会调用这个方法。object存储了请求的信息。如;rul

2、userdetailsservice

用户登录,会先调用这里面的 loaduserbyusername。通过用户名去查询用户是否存在数据库。

​ 在这里面进行查询,获得用户权限信息

3、accessdecisionmanager

里面的decide方法。

// decide 方法是判定是否拥有权限的决策方法,
    //authentication 是释userservice中循环添加到 grantedauthority 对象中的权限信息集合.
    //object 包含客户端发起的请求的requset信息
    ,可转换为 httpservletrequest request = ((filterinvocation) object).gethttprequest();
    //configattributes 为myinvocationsecuritymetadatasource的getattributes(object object)这个方法返回的结果,
    此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,
    用来判定用户是否有此权限。如果不在权限表中则放行。
    @override
    public void decide(authentication authentication, object o, collection<configattribute> configattributes)

2、正式实战了

1 使用idea的srping initializr 创建一个项目 我的版本如下pom.xml

<?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.example</groupid>
    <artifactid>demo</artifactid>
    <version>0.0.1-snapshot</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>demo project for spring boot</description>

    <parent>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-parent</artifactid>
        <version>1.5.9.release</version>
        <relativepath/> <!-- lookup parent from repository -->
    </parent>


    <properties>
        <project.build.sourceencoding>utf-8</project.build.sourceencoding>
        <project.reporting.outputencoding>utf-8</project.reporting.outputencoding>
        <java.version>1.8</java.version>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        <mybatis.version>3.2.7</mybatis.version>
        <mybatis-spring.version>1.2.2</mybatis-spring.version>
    </properties>



    <dependencies>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-aop</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-security</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-thymeleaf</artifactid>
        </dependency>
        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-web</artifactid>
        </dependency>

        <dependency>
            <groupid>org.springframework.boot</groupid>
            <artifactid>spring-boot-starter-test</artifactid>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupid>org.springframework.security</groupid>
            <artifactid>spring-security-test</artifactid>
            <scope>test</scope>
        </dependency>
        <!--提供security相关标签,可选可不选-->
        <dependency>
            <groupid>org.thymeleaf.extras</groupid>
            <artifactid>thymeleaf-extras-springsecurity4</artifactid>
        </dependency>
        <!--bootstrap组件,可选可不选-->
        <dependency>
            <groupid>org.webjars</groupid>
            <artifactid>bootstrap</artifactid>
            <version>3.3.7</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupid>mysql</groupid>
            <artifactid>mysql-connector-java</artifactid>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupid>com.mchange</groupid>
            <artifactid>c3p0</artifactid>
            <version>0.9.5.2</version>
            <exclusions>
                <exclusion>
                    <groupid>commons-logging</groupid>
                    <artifactid>commons-logging</artifactid>
                </exclusion>
            </exclusions>
        </dependency>

        <!--mybatis-->
        <dependency>
            <groupid>org.springframework</groupid>
            <artifactid>spring-jdbc</artifactid>
        </dependency>
        <dependency>
            <groupid>org.mybatis</groupid>
            <artifactid>mybatis</artifactid>
            <version>${mybatis.version}</version>
        </dependency>
        <dependency>
            <groupid>org.mybatis</groupid>
            <artifactid>mybatis-spring</artifactid>
            <version>${mybatis-spring.version}</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupid>org.springframework.boot</groupid>
                <artifactid>spring-boot-maven-plugin</artifactid>
            </plugin>
        </plugins>
    </build>
</project>

2,创建一个springsecurity配置类,你也可以使用配置文件的方法。我这里使用了boot的配置类

package com.example.config;

import com.example.service.customuserservice;
import com.example.service.myfiltersecurityinterceptor;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.security.config.annotation.authentication.builders.authenticationmanagerbuilder;
import org.springframework.security.config.annotation.web.builders.httpsecurity;
import org.springframework.security.config.annotation.web.configuration.enablewebsecurity;
import org.springframework.security.config.annotation.web.configuration.websecurityconfigureradapter;
import org.springframework.security.core.userdetails.userdetailsservice;
import org.springframework.security.web.access.intercept.filtersecurityinterceptor;


@configuration  //声明为配置类
@enablewebsecurity  //这里启动security
public class springsecurityconfig extends websecurityconfigureradapter{

    @autowired  //下面会编写这个类
    private myfiltersecurityinterceptor myfiltersecurityinterceptor;

    @autowired   //下面会编写这个类
    private defaultaccessdeniedhandler defaultaccessdeniedhandler;

    @bean   
    userdetailsservice customuserservice(){ //注册userdetailsservice 的bean
        return new customuserservice();
    }
    @override
    protected void configure(authenticationmanagerbuilder auth) throws exception {
        auth.userdetailsservice(customuserservice()); //user details service验证
    }

    @override
    protected void configure(httpsecurity http) throws exception {
        http.exceptionhandling()
                .accessdeniedhandler(defaultaccessdeniedhandler);
        http.authorizerequests()
                .antmatchers("/css/**").permitall()
                .anyrequest().authenticated() //任何请求,登录后可以访问
                .and()
                .formlogin().loginpage("/login").failureurl("/login?error").permitall() //登录页面用户任意访问
                .and()
                .logout().permitall(); //注销行为任意访问
        http.addfilterbefore(myfiltersecurityinterceptor, filtersecurityinterceptor.class);
    }

}

3、自定义securitymetadatasource拦截器

package com.example.service;

import com.example.dao.permissiondao;
import com.example.domain.permission;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.security.access.configattribute;
import org.springframework.security.access.securityconfig;
import org.springframework.security.web.filterinvocation;
import org.springframework.security.web.access.intercept.filterinvocationsecuritymetadatasource;
import org.springframework.security.web.util.matcher.antpathrequestmatcher;
import org.springframework.stereotype.service;

import javax.servlet.http.httpservletrequest;
import java.util.*;

/**
 */
@service
public class myinvocationsecuritymetadatasourceservice  implements
        filterinvocationsecuritymetadatasource {


    private hashmap<string, collection<configattribute>> map =null;

    @autowired
    private permissiondao permissiondao;

    /**
     * 自定义方法。最好在项目启动时,去数据库查询一次就好。
     * 数据库查询一次 权限表出现的所有要拦截的url
     */
    public void loadresourcedefine(){
        map = new hashmap<>();
        collection<configattribute> array;
        configattribute cfg;
        //去数据库查询 使用dao层。 你使用自己的即可
        list<permission> permissions = permissiondao.findall();
        for(permission permission : permissions) {
            array = new arraylist<>();
            //下面你可以添加你想要比较的信息过去。 注意的是,需要在用户登录时存储的权限信息一致
            cfg = new securityconfig(permission.getname());
            //此处添加了资源菜单的名字,例如请求方法到configattribute的集合中去。此处添加的信息将会作为myaccessdecisionmanager类的decide的第三个参数。
           
            array.add(cfg);
            //用权限的geturl() 作为map的key,用configattribute的集合作为 value,
            map.put(permission.geturl(), array);
        }

    }

    //此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
    @override
    public collection<configattribute> getattributes(object object) throws illegalargumentexception {
        filterinvocation filterinvocation = (filterinvocation) object;
        string fullrequesturl = filterinvocation.getfullrequesturl();
        //若是静态资源 不做拦截  下面写了单独判断静态资源方法
        if (ismatcherallowedrequest(filterinvocation)) {
            system.out.println("我没有被拦截"+fullrequesturl);
           return null;
        }
        //map 为null 就去数据库查
        if(map ==null)  {
         loadresourcedefine();
        }
        //测试 先每次都查
        //object 中包含用户请求的request 信息


        httpservletrequest request = filterinvocation.gethttprequest();
        antpathrequestmatcher matcher;
        string resurl;
        for(iterator<string> iter = map.keyset().iterator(); iter.hasnext(); ) {
            resurl = iter.next();
            matcher = new antpathrequestmatcher(resurl);
            if(matcher.matches(request)) {
                return map.get(resurl);
            }
        }
        return null;
    }


    /**
     * 判断当前请求是否在允许请求的范围内
     * @param fi 当前请求
     * @return 是否在范围中
     */
    private boolean ismatcherallowedrequest(filterinvocation fi){
        return allowedrequest().stream().map(antpathrequestmatcher::new)
                .filter(requestmatcher -> requestmatcher.matches(fi.gethttprequest()))
                .toarray().length > 0;
    }

    /**
     * @return 定义允许请求的列表
     */
    private list<string> allowedrequest(){
        return arrays.aslist("/login","/css/**","/fonts/**","/js/**","/scss/**","/img/**");
    }


    @override
    public collection<configattribute> getallconfigattributes() {
        return null;
    }

    @override
    public boolean supports(class<?> clazz) {
        return true;
    }
}

自定义userdetailsservice 。登录的时候根据用户名去数据库查询用户拥有的权限信息

package com.example.service;

import com.example.dao.permissiondao;
import com.example.dao.userdao;
import com.example.domain.permission;
import com.example.domain.sysrole;
import com.example.domain.sysuser;
import org.springframework.beans.factory.annotation.autowired;
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.service;

import java.util.arraylist;
import java.util.list;

/**
 * created by yangyibo on 17/1/18.
 */
@service
public class customuserservice implements userdetailsservice { //自定义userdetailsservice 接口

    @autowired
    userdao userdao;
    @autowired
    permissiondao permissiondao;

    public userdetails loaduserbyusername(string username) {
        sysuser user = userdao.findbyusername(username);
        for (sysrole role : user.getroles()) {
            system.out.println(role.getname());
        }
        if (user != null) {
            //根据用户id 去查找用户拥有的资源
            list<permission> permissions = permissiondao.findbyadminuserid(user.getid());
            list<grantedauthority> grantedauthorities = new arraylist <>();
            for (permission permission : permissions) {
                if (permission != null && permission.getname()!=null) {

                    grantedauthority grantedauthority = new simplegrantedauthority(permission.getname());
                    //1:此处将权限信息添加到 grantedauthority 对象中,在后面进行全权限验证时会使用grantedauthority 对象。
                    grantedauthorities.add(grantedauthority);
                }
            }
            return new user(user.getusername(), user.getpassword(), grantedauthorities);
        } else {
            throw new usernamenotfoundexception("admin: " + username + " do not exist!");
        }
    }

}

自定义accessdecisionmanager

package com.example.service;

import org.springframework.security.access.accessdecisionmanager;
import org.springframework.security.access.accessdeniedexception;
import org.springframework.security.access.configattribute;
import org.springframework.security.authentication.insufficientauthenticationexception;
import org.springframework.security.core.authentication;
import org.springframework.security.core.grantedauthority;
import org.springframework.stereotype.service;

import java.util.collection;
import java.util.iterator;

@service
public class myaccessdecisionmanager implements accessdecisionmanager {

    // decide 方法是判定是否拥有权限的决策方法,
    //authentication 是释customuserservice中循环添加到 grantedauthority 对象中的权限信息集合.
    //object 包含客户端发起的请求的requset信息,可转换为 httpservletrequest request = ((filterinvocation) object).gethttprequest();
    //configattributes 为myinvocationsecuritymetadatasource的getattributes(object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
    @override
    public void decide(authentication authentication, object o, collection<configattribute> configattributes) throws accessdeniedexception, insufficientauthenticationexception {
        if (null == configattributes || configattributes.size() <= 0 ) {
            return;
        }
        configattribute c;
        string needrole;

        for (iterator<configattribute> iter = configattributes.iterator(); iter.hasnext(); ) {
            c = iter.next();
            needrole = c.getattribute();
            for (grantedauthority ga : authentication.getauthorities()) { //authentication 为在注释1 中循环添加到 grantedauthority 对象中的权限信息集合
                if (needrole.trim().equals(ga.getauthority())) {
                    return;
                }
            }
        }
        throw new accessdeniedexception("no right");
    }

    @override
    public boolean supports(configattribute configattribute) {
        return true;
    }

    @override
    public boolean supports(class<?> aclass) {
        return true;
    }
}

自定义拦截器

package com.example.service;

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.security.access.securitymetadatasource;
import org.springframework.security.access.intercept.abstractsecurityinterceptor;
import org.springframework.security.access.intercept.interceptorstatustoken;
import org.springframework.security.web.filterinvocation;
import org.springframework.security.web.access.intercept.filterinvocationsecuritymetadatasource;
import org.springframework.stereotype.service;

import javax.servlet.filter;
import javax.servlet.filterchain;
import javax.servlet.filterconfig;
import javax.servlet.servletexception;
import javax.servlet.servletrequest;
import javax.servlet.servletresponse;
import java.io.ioexception;


@service
public class myfiltersecurityinterceptor extends abstractsecurityinterceptor implements filter {

    @autowired
    private filterinvocationsecuritymetadatasource securitymetadatasource;

    @autowired
    private void setmyaccessdecisionmanager(myaccessdecisionmanager myaccessdecisionmanager) {
        super.setaccessdecisionmanager(myaccessdecisionmanager);
    }


    @override
    public void init(filterconfig filterconfig) throws servletexception {

    }


    @override
    public void dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain filterchain) throws ioexception, servletexception {
        filterinvocation fi = new filterinvocation(servletrequest, servletresponse, filterchain);
        invoke(fi);
    }

    public void invoke(filterinvocation fi) throws ioexception, servletexception {
//fi里面有一个被拦截的url
//里面调用myinvocationsecuritymetadatasource的getattributes(object object)这个方法获取fi对应的所有权限
//再调用myaccessdecisionmanager的decide方法来校验用户的权限是否足够
        interceptorstatustoken token = super.beforeinvocation(fi);
        try {
//执行下一个拦截器
            fi.getchain().dofilter(fi.getrequest(), fi.getresponse());
        } finally {
            super.afterinvocation(token, null);
        }
    }

    @override
    public void destroy() {

    }

    @override
    public class<?> getsecureobjectclass() {
        return filterinvocation.class;
    }

    @override
    public securitymetadatasource obtainsecuritymetadatasource() {
        return this.securitymetadatasource;
    }
}

运行项目就实现了。去试试吧。
记得将自定义拦截器放进security的过滤器链中。

到此这篇关于springsecurity实现动态url拦截(基于rbac模型)的文章就介绍到这了,更多相关springsecurity 动态url拦截内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!