SpringBoot中Shiro处理ajax请求(重写UserFilter)

首先道歉 没经过充分的测试就发文了 后来在review的时候发现我在map中同一个key塞了俩对象

这样只有最后添加的有效 在看了shiro相关文档之后找到了有效的解决方法

文章末尾我会补上Shiro自带的拦截器相关内容

 

写一个Shiro的过滤器 继承org.apache.shiro.web.filter.authc.UserFilter

import com.zzyk.common.model.vo.Message;
import com.alibaba.fastjson.JSON;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.UserFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class GenericFilter extends UserFilter {

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;

        resp.setCharacterEncoding("UTF-8");
        resp.setHeader("ContentType", "text/html;charset=UTF-8");
        String requestedWith = req.getHeader("X-Requested-With");

        if ("XMLHttpRequest".equals(requestedWith)) {
            Message message = new Message();
            message.setCode(403);
            message.setMessage("请登录后操作");
            resp.getWriter().write(JSON.toJSONString(message));
        } else {
            this.saveRequestAndRedirectToLogin(request, response);
        }
        return false;
    }
}

 

Shiro的配置类里面的配置我就全部放出来了 就看一下与这次配置相关的

@Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        // 设置登录界面URL
        factoryBean.setLoginUrl(loginUrl);
        // 设置未经认证页面的URL
        factoryBean.setUnauthorizedUrl(unauthorizedUrl);
        // 设置登录成功后跳转的URL
        factoryBean.setSuccessUrl(indexUrl);

        HashMap<String, Filter> filter = new HashMap<>();
        filter.put("authc", new GenericFilter());
        filter.put("logout", new LogoutFilter());
        factoryBean.setFilters(filter);

        // 需要认证的加到authc里面
        // 不需要认证的加到anon里面
        HashMap<String, String> filterChain = new HashMap<>();
        filterChain.put("/customize/**", "anon");
        filterChain.put("/plugins/**", "anon");
        filterChain.put("/layuiadmin/**", "anon");
        filterChain.put("/favicon.ico", "anon");
        filterChain.put("/sys/login", "anon");
        filterChain.put("/sys/status", "anon");
        filterChain.put("/sys/captcha", "anon");
        filterChain.put("/device/notice", "anon");
        filterChain.put("/druid/**", "anon");
        filterChain.put("/sys/logout", "logout");

        filterChain.put("/**", "authc");
        factoryBean.setFilterChainDefinitionMap(filterChain);

        return factoryBean;
    }

另外不知道为啥我用jquery的ajax发出的请求都没有X-Requested-With请求头(郁闷...)

我就包装了一下jquery的ajax 手动把这个请求头加上 顺便处理了一下跨域问题

function getJson(url, params, method, success) {
    $.ajax({
        url: host + url,
        data: params,
        method: method,
        async: true,
        dataType: "json",
        xhrFields: {
            withCredentials: true
        },
        crossDomain: true,
        beforeSend: function (xhr) {
            xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest")
        },
        success: function (data) {
            if (data['code'] == 403) {
                alert(data['message']);
                top.location.href = 'login.html'
            } else {
                if (success) {
                    success(data);
                }
            }
        }, error: function () {
            alert('服务器错误,请联系管理员');
        }
    });
}

这样ajax和网页请求都能正常处理了


注意一个过滤器名只能配一个过滤器 一个资源可以配多个过滤器名 方法为逗号分割 例如

// 定义过滤器
HashMap<String, Filter> filter = new HashMap<>(); filter.put("authc", new GenericFilter()); filter.put("default", new FormAuthenticationFilter()); filter.put("logout", new LogoutFilter()); factoryBean.setFilters(filter);
// 定义过滤链 HashMap
<String, String> filterChain = new HashMap<>(); filterChain.put("/**", "authc,default"); factoryBean.setFilterChainDefinitionMap(filterChain);

 

DefaultFilterChainManager 会默认添加 org.apache.shiro.web.filter.mgt.DefaultFilter 中声明的拦截器

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); 
} 

拦截器说明

默认拦截器名 拦截器类 说明 主要参数
身份验证相关 org.apache.shiro.web.filter.authc
authc FormAuthenticationFilter

基于表单的拦截器

usernameParam: 用户名(username)

passwordParam: 密码(password)

rememberMeParam: 记住密码(remember)

loginUrl: 登录页面("/login.jsp")

successUrl: 登录成功后重定向的页面

failureKeyAttribute: 登录失败后

    错误信息存储(shiroLoginFailure)

authcBasic BasicHttpAuthenticationFilter

Basic HTTP身份验证拦截器

就是浏览器弹出登录窗口的那种

applicationName: 登录框显示的信息(application)
logout LogoutFilter 退出登录拦截器 redirectUrl: 退出登录重定向的页面("/")
user UserFilter

用户拦截器

用于验证用户是否通过身份验证

 
anon AnonymousFilter 匿名拦截器 无需认证即可访问  
授权相关 org.apache.shiro.web.filter.authz
roles RolesAuthorizationFilter 角色授权拦截器

loginUrl: 登录页面("/login.jsp")

unauthorizedUrl: 未授权跳转的页面

perms PermissionsAuthorizationFilter 权限授权拦截器  

未完全实现

1.3.2版本不可用

HostFilter

主机地址拦截器

我调用直接抛异常说暂未实现

authorizedIps: 已授权的ip地址

deniedIPS: 已拒绝的ip地址

port PortFilter 端口拦截器

port: 允许通过的端口

如果是非指定端口访问 则重定向到该端口

rest HttpMethodPermissionFilter

rest风格拦截器 根据请求方法构建权限字符串

GET=read

POST=create

PUT=update

DELETE=delete

HEAD=read

TEACE=read

OPTIONS=read

MKCOL=create

ssl SslFilter SSL拦截器

无参数 只允许https请求通过

如果是非http请求会重定向到443端口

其他
org.apache.shiro.web.filter.session
noSessionCreation NoSessionCreationFilter

不创建会话(Session)拦截器

调用subject.getSession(false)没问题

调用subject.getSession(true)会抛异常

DisabledSessionException

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

节选自《跟我学SHiro》并重新排版,修改了部分内容

posted on 2020-06-06 00:12  绝对密位  阅读(1997)  评论(0编辑  收藏  举报

导航