jfinal+freemarker+shiro的简单实现

时间:2021-06-24 18:21:41

最近两天研究了一下jfinal+freemarker+shiro。也在网上搜索了好多资料,最后弄出来一个简单的实现。记录下来,希望共同学习。

1.首先需要现在web.xml中添加jfinal和shiro的过滤器和shiro的listener,如下:

    <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>
</filter-mapping>

<filter>
<filter-name>jfinal</filter-name>
<filter-class>com.jfinal.core.JFinalFilter</filter-class>
<init-param>
<param-name>configClass</param-name>
<param-value>com.shiro.config.MyShiroConfig</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jfinal</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

要使shiro的过滤器在jfinal之上,保证经过shiro验证的请求才能进入jfinal的验证。而且shiro的filter默认回去像个位置寻找shiro.ini配置文件

(1)/WEB-INF/shiro.ini(2)classpath的根目录,那个先找到用那个。

也可以指定shiro.ini的位置,在filter中添加配置

<init-param>
<param-name>config
Paht</param-name>
<param-value>
classpath:shiro.ini</param-value>
</init-param>

2.shiro.ini

--------------------数据源---------------------------

ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = localhost
ds.user = root
ds.password = 123456
ds.databaseName = jfinal_shiro

     jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.authenticationQuery = SELECT password FROM users WHERE username = ?
jdbcRealm.userRolesQuery = SELECT r.role_name FROM roles AS r, user_roles AS ur WHERE r.id = ur.role_id AND ur.user_id = (SELECT id FROM users WHERE u sername = ?)
jdbcRealm.permissionsQuery = SELECT p.permission FROM permissions AS p, roles_permissions AS rp WHERE p.id = rp.permission_id AND rp.role_id = (SELEC T id FROM roles WHERE role_name = ?)
securityManager.realm = $jdbcRealm

jdbcRealm.dataSource = $ds

ds指定了数据源,并通过jdbcRealm.dataSource = $ds注入到jdbcRealm中。

jdbcRealm.authenticationQuery,jdbcRealm.userRolesQuery,jdbcRealm.permissionsQuery配置行配置了权限相关的查询语句,它告诉shiro如何获取权限信息,他们都是用查询后的第一个字段来进行验证的。

jdbcRealm.authenticationQuery取的是查询后第一条记录的第一个字段进行验证。

jdbcRealm.userRolesQuery取的是查询记录后第一个字段(role角色)座位所属角色(可以有多个角色)。

jdbcRealm.permissionsQuery取的是查询后的第一个字段的权限值做为验证,同样也可以有多个。

------------------------缓存-------------------------

#cache
shiroCacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
shiroCacheManager.cacheManagerConfigFile = classpath:ehcache-shiro.xml
securityManager.cacheManager = $shiroCacheManager

---------------------session配置---------------------------

#session
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionDAO.activeSessionsCacheName = shiro-activeSessionCache
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager


securityManager.sessionManager = $sessionManager
securityManager.sessionManager.sessionDAO = $sessionDAO

securityManager.cacheManager = $shiroCacheManager这句话为shiro所有组件配置了一个cacheManger.同时会注入到sessionDao中,因为EnterpriseCacheSessionDAO实现了cacheManagerAware接口的性质,实现了注入

authc.loginUrl=/jsp/login.html

------------urls----------------

[urls]  
/student/*=authc

/student/*=authc这句话的意思是进行权限验证,验证不通过则跳转到authc.loginUrl=/jsp/login.html所指向的地址。

因为我项目中用的是jfinal和freemarker,jfinal比较简单入手,这是加上shiro之后,可以自定freemarker的方法。如下:

 public class CheckPermissionMethod implements TemplateMethodModel {
    @Override
    public Object exec(List list) throws TemplateModelException {
        if (null == list || 1 != list.size()) {
            throw new TemplateModelException("Arguments wrong:one argument is allowed");
        }
        String permission = (String) list.get(0);
        return permission != null && permission.length() > 0 && getSubject() != null
                && getSubject().isPermitted(permission);
    }


    private static Subject getSubject() {
        return SecurityUtils.getSubject();
    }
}

注:其他的方法如hasrole等同上

然后在interceptor中执行如下代码,将模板方法添加进去

public class ShiroFreemarkerTemplateInterceptor implements Interceptor {
    @Override
    public void intercept(ActionInvocation ai) {
        Controller c = ai.getController();
        c.setAttr("hasPermission", new CheckPermissionMethod());
        ai.invoke();
    }
}

然后在jfinal的config中configInterceptor方法中执行

me.add(new ShiroFreemarkerTemplateInterceptor());

之后就可以在ftl文件中使用freemarker标签执行改方法了,如:

<#if hasPermission("addUser")>
            <a href="/student/add">添加</a>
</#if>

其实shiro有自己的标签。但是ftl又不能像jsp那样引入标签库,于是找了半天,有一种方式可以解决,

导入jar包:shiro-web-1.2.3.jar;shiro-freemarker-tags-0.1-SNAPSHOT.jar

在jfinal的config的configConstant方法中加如下代码

Configuration cfg = FreeMarkerRender.getConfiguration();
        cfg.setDefaultEncoding("utf-8");
        cfg.setSharedVariable("shiro", new ShiroTags());

即可在页面中使用shiro的标签,但是方式会有点变化,比如我想判断用户登陆了,显示用户名

<@shiro.user>
            hello!<@shiro.principal/> how are you today?
</@shiro.user>

以上是自己完成一个小的demo之后的心得吧,希望能够对不懂这块的朋友有一点点帮助。如果哪有写的不准确的继续交流学习。