基于jfinal Template的Shiro 标签

时间:2022-04-27
本文章向大家介绍基于jfinal Template的Shiro 标签,主要内容包括继承Directiv形式、共享对象扩展、指令注解加载、PS、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

jfinal template 经过 3.0、3.1 两个版本的迭代,已经非常稳定优秀了,所以我从传统的jsp 迁移到了jf template ,jsp中使用shiro 的标签库,可以很方便的实现权限的控制例如:

<shiro:guest>  
    用户未登录状态显示
</shiro:guest>  

<shiro:user>  
    欢迎[<shiro:principal/>]登录
</shiro:user>  

结合jf模板灵活指令扩展,来实现这么一套标签非常简单。

继承Directiv形式

public class GuestTag extends Directiv {
    private Subject getSubject() {
        return SecurityUtils.getSubject();
    }
    
    public void exec(Env env, Scope scope, Writer writer) {
        if (getSubject() == null || getSubject().getPrincipal() == null)
            stat.exec(env, scope, writer);
    }

    public boolean hasEnd() {
        return true;
    }
}


在config中配置
public void configEngine(Engine me) {
     me.addDirective("guest", new GuestTag());
}

页面中使用
#guest()
    用户未登录状态显示
#end

带入参类型标签处理

public class HasRoleTag extends Directiv {
    private Expr[] exprs;
    
     private Subject getSubject() {
        return SecurityUtils.getSubject();
    }
    
    public void setExprList(ExprList exprList) {
        exprs = exprList.getExprArray();
    }

    public void exec(Env env, Scope scope, Writer writer) {
        boolean hasRole = false;
        if (getSubject() != null && ArrayUtil.isNotEmpty(exprs))
            if (getSubject().hasRole(exprs[0].toString()))
                hasRole = true;

        if (hasRole)
            stat.exec(env, scope, writer);
    }

    public boolean hasEnd() {
        return true;
    }

}


页面中使用

#hasRole(roleName)
    body
#end

共享对象扩展

使用这种形式就更舒服了

public class ShiroTag {
    private Subject getSubject() {
        return SecurityUtils.getSubject();
    }
   
    public boolean isGuest() {
        return getSubject() == null || getSubject().getPrincipal() == null;
    }
 
    public boolean hasRole(String roleName) {
        return getSubject() != null && getSubject().hasRole(roleName);
    }
 
  
    public boolean lacksRole(String roleName) {
        boolean hasRole = getSubject() != null
                && getSubject().hasRole(roleName);
        return !hasRole;
    }
}

config中配置一下

public void configEngine(Engine me) {
    me.addSharedObject("shiro",ShiroTag);
}

页面使用
#if(shiro.hasRole(roleName))
body
#end

打完 收工~

指令注解加载

shiro标签种类很多,具体的逻辑也可以自己实现,所以我们写好以后,配置在config 是一件比较痛苦的事情,稍不留神,就配置错误了。所以我们可以通过注解扫描的形式方便配置。(其他自定义指令 也可以使用,方法相同)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//@Inherited 不继承
public @interface DefineDirective {
    /**
     * 标签名称
     *
     * @return String
     */
    String tag() default "";
}


@DefineDirective(tag = "hasRole")
public class HasRoleTag extends Directiv {...}

然后写这么一个EngineKit

    //classUtils  使用的是 hutool 工具包的方法。。。
    public static void addShiroDefineDirective(Engine me) {
        Set<Class<?>> classes = ClassUtil.scanPackageByAnnotation(defineDirective, DefineDirective.class);
        for (Class<?> clazz : classes) {
            DefineDirective defineDirective = clazz.getAnnotation(DefineDirective.class);
            String tag = defineDirective.tag();
            if (StrUtil.isNotEmpty(tag)) {
                me.addDirective(tag, (Directive) ClassUtil.newInstance(clazz));
            } else {
                LogKit.error("自定义Directive的标签为空无效:" + clazz.getName());
            }
        }
    }

config中配置一下

public void configEngine(Engine me) {
    EngineKit.addShiroDefineDirective(me);
}

PS

当然上边的扩展,并没有和我们的shiro插件集成,我实现了一个与JfinalShiroPlugin@玛雅牛无缝集成的版本内置这个shiro标签,原理类似。

JfinalShiroPlugin: http://git.oschina.net/log4j/jfinalshiroplugin

然后具体使用项目整合栗子: http://git.oschina.net/log4j/LMS