Shiro 改造成 Restful 风格

Apache Shiro 具有两种认证方式:①Filter 认证方式;②注解认证方式:在需要认证的方法上添加注解 @RequiresAuthentication、@RequiresPermissions、@RequiresRoles 等等


1.针对 Filter 的认证方式

Apache Shiro 默认配置了 11 个 Filter,分别是

public enum DefaultFilter {

    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);

    private final Class<? extends Filter> filterClass;

    private DefaultFilter(Class<? extends Filter> filterClass) {
        this.filterClass = filterClass;
    }

    //......
}
  • 可以对其核心的几个 Filter 进行改写,以实现自己的需求
    1. authc,使得在用户未认证时返回 JSON 信息
    2. logout,使得在注销时返回 JSON(有BUG,一旦配置好,所有请求都会进入此Filter,即所有请求必会进行注销,放弃之)
    3. perms,使得在非法用户权限时返回 JSON
    4. roles,使得在非法用户角色时返回 JSON

项目相关参数

@Component
@ConfigurationProperties(prefix="project")
public class Project {

    //未登录
    public static final Integer NO_LOGIN_CODE = 1;
    public static final String NO_LOGIN_MESSAGE = "请先进行登录";

    //登录成功
    public static final Integer LOGIN_SUCCESS_CODE = 2;
    public static final String LOGIN_SUCCESS_MESSAGE = "登录成功";

    //登录失败
    public static final Integer LOGIN_FAILURE_CODE = 3;
    public static final String LOGIN_FAILURE_MESSAGE = "登录失败";

    //注销
    public static final Integer LOGOUT_CODE = 4;
    public static final String LOGOUT_MESSAGE = "注销成功";

    //缺少用户权限
    public static final Integer NO_AUTH_CODE = 5;
    public static final String NO_AUTH_MESSAGE = "权限不足";

    //缺少用户角色
    public static final Integer NO_ROLE_CODE = 6;
    public static final String NO_ROLE_MESSAGE = "用户角色不符合";

    public static HttpServletResponse servletResponseProcess(ServletResponse response){
        HttpServletResponse res = (HttpServletResponse)response;
        res.setContentType("application/json;charset=UTF-8");
        return res;
    }
}

由于 Apache Shiro 框架的灵活性,我们可以自定义派生类来继承这几个 Filter,并重写相关方法以实现自定义的 Restful 逻辑

1.authc,继承 FormAuthenticationFilter.class

public class MyFormAuthenticationFilter extends FormAuthenticationFilter {

    //在用户未认证时调用
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
//        return super.onAccessDenied(request, response, mappedValue);

        HttpServletResponse res = Project.servletResponseProcess(response);
        //输出 JSON 字符串
        res.getWriter().print(
                JSON.toJSON(
                        Result.returnError(Project.NO_LOGIN_CODE, Project.NO_LOGIN_MESSAGE)));
        //中止请求,不再传给下一个Filter
        return false;
    }
}

2.logout,继承 LogoutFilter.class(配置之后出现了莫名其妙的问题,不推荐使用,建议编写代码 Subject.logout(); 手动注销)

3.perms,继承 PermissionsAuthorizationFilter.class

public class MyPermissionsAuthorizationFilter extends PermissionsAuthorizationFilter {

    //在非法用户权限时调用
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
//        return super.onAccessDenied(request, response, mappedValue);

        //获取被要求的权限
        String[] perms = (String[]) mappedValue;
        HttpServletResponse res = Project.servletResponseProcess(response);
        //输出 JSON 字符串
        res.getWriter().print(
                JSON.toJSON(
                        Result.returnError(Project.NO_AUTH_CODE,
                                Project.NO_AUTH_MESSAGE + Arrays.toString(perms))));
        //中止请求,不再传给下一个Filter
        return false;
    }
}

4.roles,继承 RolesAuthorizationFilter.class

public class MyRolesAuthorizationFilter extends RolesAuthorizationFilter {

    //在非法用户角色时调用
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
//        return super.onAccessDenied(request, response, mappedValue);

        //获取被要求的角色
        String[] rolesArray = (String[]) mappedValue;
        HttpServletResponse res = Project.servletResponseProcess(response);
        //输出 JSON 字符串
        res.getWriter().print(
                JSON.toJSON(
                        Result.returnError(Project.NO_ROLE_CODE,
                                Project.NO_ROLE_MESSAGE + Arrays.toString(rolesArray))));
        //中止请求,不再传给下一个Filter
        return false;
    }
}

最后一步,配置这几个自定义类,以覆盖默认配置,从而使得我们的代码生效(编辑Spring配置applicationContext.xml)

<!--Shiro 核心过滤器/拦截器,拦截一切请求-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>

        <property name="filters">
            <util:map>
                <entry key="authc" value-ref="myFormAuthenticationFilter"/>
                <entry key="perms" value-ref="myPermissionsAuthorizationFilter"/>
                <entry key="roles" value-ref="myRolesAuthorizationFilter"/>
            </util:map>
        </property>

        <property name="filterChainDefinitions">
            <value>
                # some example chain definitions:
                #/admin/** = authc, roles[admin]
                #/docs/** = authc, perms[document:read]
                #/** = authc
                # more URL-to-FilterChain definitions here

                #(从上往下匹配,局部配置放顶部,全局配置放底部)
                /0/** = authc
                /1/** = roles[admin]
                /2/** = perms[user:delete]
                /3/** = perms[user:delete,user:manage,user:hello]
                /** = anon
            </value>
        </property>
    </bean>

    <!--自定义的 Filter 派生类-->
    <bean id="myFormAuthenticationFilter" class="com.cstor.safe.config.shiro.MyFormAuthenticationFilter"/>
    <bean id="myPermissionsAuthorizationFilter" class="com.cstor.safe.config.shiro.MyPermissionsAuthorizationFilter"/>
    <bean id="myRolesAuthorizationFilter" class="com.cstor.safe.config.shiro.MyRolesAuthorizationFilter"/>

打开浏览器,依次访问网站的URL: /0、/1、/2、/3,得到内容为

{"errorCode":"1","resultFlag":false,"message":"请先进行登录"}

{"errorCode":"6","resultFlag":false,"message":"用户角色不符合[admin]"}

{"errorCode":"5","resultFlag":false,"message":"权限不足[user:delete]"}

{"errorCode":"5","resultFlag":false,"message":"权限不足[user:delete, user:manage, user:hello]"}

2.针对注解的认证方式

  • 对于 @RequiresAuthentication、@RequiresPermissions、@RequiresRoles 等相关注解,Shiro 框架并未提供开发者介入的机会,一旦认证不通过,就会在注解方法处抛出异常(可以采用全局异常处理器,进行统一处理)
    • @RequiresAuthentication,如果用户未登录,抛出异常 UnauthenticatedException
    • @RequiresRoles,如果用户角色不符合,抛出异常 UnauthorizedException
    • @RequiresPermissions,如果用户权限不符合,抛出异常 UnauthorizedException
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值