Jfinal与shiro集成实现动态URL鉴权,不装插件只需要一个类

来源:互联网 发布:如何在淘宝发布产品 编辑:程序博客网 时间:2024/06/11 05:16

Jfinal与Shiro集成,有玛雅牛和dreamip两个Jfinal插件,但还是想以简单的方式实现动态URL鉴权。

本人的实现思路是,利用Shiro本身的过滤器扩展来实现动态通过数据库URL授权。方法如下:

1. 新建一个JFinal Maven项目

2. pom.xml中添加对Shiro的引用:

        <dependency>            <groupId>org.apache.shiro</groupId>            <artifactId>shiro-all</artifactId>            <version>1.2.3</version>        </dependency>
3. /WEB-INF/web.xml中加入shiro的支持

    <listener>        <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>    </listener>    <filter>        <filter-name>shiroFilter</filter-name>        <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>    </filter>    <filter-mapping>        <filter-name>shiroFilter</filter-name>        <url-pattern>/*</url-pattern>        <dispatcher>REQUEST</dispatcher>        <dispatcher>FORWARD</dispatcher>        <dispatcher>INCLUDE</dispatcher>        <dispatcher>ERROR</dispatcher>    </filter-mapping>

4. resource目录下新增配置文件shiro.ini

[main]shiro.loginUrl = /auth/loginjdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealmdataSource = com.mysql.jdbc.jdbc2.optional.MysqlDataSourcedataSource.serverName = localhostdataSource.user = rootdataSource.password = rootdataSource.databaseName = jinlujdbcRealm.dataSource = $dataSourcejdbcRealm.authenticationQuery = SELECT password  FROM sec_user WHERE status=1 AND username = ?jdbcRealm.userRolesQuery = SELECT r.role_name FROM sec_role AS r, sec_user_role AS ur WHERE r.id = ur.role_id AND r.status=1 AND ur.user_id = (SELECT id FROM sec_user WHERE username = ?)jdbcRealm.permissionsQuery = SELECT p.permission FROM sec_permission AS p, sec_role_permission AS rp WHERE p.id = rp.permission_id AND rp.role_id = (SELECT id FROM sec_role WHERE role_name = ?)jdbcRealm.permissionsLookupEnabled = truesecurityManager.realms = $jdbcRealmpasswordMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcherpasswordMatcher.hashAlgorithmName=MD5jdbcRealm.credentialsMatcher=$passwordMatcher#cacheshiroCacheManager = org.apache.shiro.cache.ehcache.EhCacheManagershiroCacheManager.cacheManagerConfigFile = classpath:ehcache.xmlsecurityManager.cacheManager = $shiroCacheManager #sessionsessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAOsessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManagersessionDAO.activeSessionsCacheName = shiro-activeSessionCachesessionManager.sessionDAO = $sessionDAOsecurityManager.sessionManager = $sessionManagersecurityManager.sessionManager.globalSessionTimeout = 3600000[filters]urlFilter=com.ziyTech.framework.interceptor.ShiroPathMatchFilter#这里的规则,web.xml中的配置的ShiroFilter会使用到。[urls]/=anon/img/**=anon/js/**=anon/css/**=anon/fonts/**=anon/uploader/**=anon/uploads/**=anon/auth/**=anon/msg/**=anon/api/**=anon/test/*=anon/**=urlFilter
其中[main]节中,jdbcRealm定义一个数据库认证域,根据那几个SQL,可以构造出相应的数据表。定义了一个MD5的密码加密算法,在[filters]节自定义了一个过滤ShiroPathMatchFilter,并且在[urls]节将其它非开放的URL鉴权都指向它。

5. ShiroPathMatchFilter实现对URL进行过滤

package com.ziyTech.framework.interceptor;import com.google.common.collect.ArrayListMultimap;import com.google.common.collect.ImmutableListMultimap;import com.google.common.collect.Multimap;import com.jfinal.log.Log;import com.jfinal.plugin.activerecord.Db;import com.jfinal.plugin.activerecord.Record;import com.ziyTech.framework.service.Conf;import com.ziyTech.framework.model.SecRole;import org.apache.shiro.subject.Subject;import org.apache.shiro.web.filter.AccessControlFilter;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import java.util.*;public class ShiroPathMatchFilter extends AccessControlFilter {    private static final Log log =  Log.getLog(Conf.class);    private static Multimap<String,String> allPermissions = ArrayListMultimap.create();    private static List<String> allRoles = new ArrayList<String>();    public static void initUrlMaps(){        log.info("start initializing permission maps.");        // 缓存所有角色        allRoles.clear();        List<SecRole> secRoles =SecRole.dao.findAll();        for(SecRole secRole:secRoles){            allRoles.add(secRole.getStr("role_name"));        }        // 缓存所有权限        allPermissions.clear();        List<Record> rolePermissions = Db.find("select r.role_name,p.permission " +                "from sec_role r,sec_permission p,sec_role_permission rp " +                "where rp.role_id=r.id and rp.permission_id=p.id and permission is not null ");        for(Record rolePermission :rolePermissions){            allPermissions.put(rolePermission.getStr("role_name"),rolePermission.getStr("permission"));        }        log.info("finished permissions map with entries:" + allPermissions.size());    }    public boolean isAccessAllowed(Subject subject,String path){        if(allPermissions.isEmpty()){            initUrlMaps();        }        for(String role : allRoles){            if(subject.hasRole(role)){                for(String url:allPermissions.get(role)){                    if(pathsMatch(url, path)){                        return true;                    }                }            }        }        return false;    }    @Override    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object o) throws Exception {        if(allPermissions.isEmpty()){            initUrlMaps();        }        Subject subject = getSubject(request, response);        for(String role : allRoles){            if(subject.hasRole(role)){                for(String url:allPermissions.get(role)){                    if(pathsMatch(url, request)){                        return true;                    }                }            }        }        return false;    }    @Override    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {        log.info("onAccessDenied");        setLoginUrl("/auth/login");        redirectToLogin(request,response);        return false;    }}

上述代码中静态变量allPermissions为MultiMap, 引这Google guava。有静态方法initUrlMaps,可在其它地方对授权信息进行初始化,如用户更改了角色,角色更改了权限时。


6. 我的鉴权相关数据库定义:

CREATE TABLE  sec_user (        id INT NOT NULL AUTO_INCREMENT,        username VARCHAR(50),        password VARCHAR(50),        email VARCHAR(100),        mobile VARCHAR(20),        avatar VARCHAR(200),        full_name VARCHAR(100),        status INT DEFAULT '1' NOT NULL,        created_at TIMESTAMP NULL,        updated_at TIMESTAMP NULL,        deleted_at TIMESTAMP NULL,        PRIMARY KEY (id)    )    ENGINE=InnoDB DEFAULT CHARSET=utf8CREATE TABLE sec_role  (        id INT NOT NULL AUTO_INCREMENT,        role_name VARCHAR(50),        description VARCHAR(200),        status INT DEFAULT '1' NOT NULL,        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE        CURRENT_TIMESTAMP,        updated_at TIMESTAMP NULL,        deleted_at TIMESTAMP NULL,        PRIMARY KEY (id)    )    ENGINE=InnoDB DEFAULT CHARSET=utf8CREATE TABLE sec_permission  (        id INT NOT NULL AUTO_INCREMENT,        permission VARCHAR(50) NOT NULL,        description VARCHAR(200) NOT NULL,        status INT DEFAULT '1' NOT NULL,        category VARCHAR(50),        name VARCHAR(50),        url VARCHAR(50),        PRIMARY KEY (id)    )    ENGINE=InnoDB DEFAULT CHARSET=utf8CREATE TABLE sec_user_role  (        id INT NOT NULL AUTO_INCREMENT,        user_id INT NOT NULL,        role_id INT NOT NULL,        PRIMARY KEY (id)    )    ENGINE=InnoDB DEFAULT CHARSET=utf8CREATE TABLE sec_role_permission (        id INT NOT NULL AUTO_INCREMENT,        role_id INT NOT NULL,        permission_id INT NOT NULL,        PRIMARY KEY (id)    )    ENGINE=InnoDB DEFAULT CHARSET=utf8

7. 使用方法

7.1 sec_permission表中,如图定义权限,指定URL pattern

7.2 通过sec_role_permission将多个权限赋予一个角色

7.3 通过sec_user_role给用户赋予角色,以实现授权

0 0
原创粉丝点击