最近两天研究了一下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>configPaht</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之后的心得吧,希望能够对不懂这块的朋友有一点点帮助。如果哪有写的不准确的继续交流学习。