zoukankan      html  css  js  c++  java
  • 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》并重新排版,修改了部分内容

    来自1942年冬季攻势中的中央集团军的037号17吨救援拖车
  • 相关阅读:
    RMAN详细教程(三):备份脚本的组件和注释
    RMAN详细教程(二):备份、检查、维护、恢复
    RMAN详细教程(一):基本命令代码
    centos6和centos7的防火墙基本命令
    如何在Centos服务器上搭建起Oracle10、VNC、以及FTP
    添加Chrome插件时出现“程序包无效”等问题的解决办法
    配置服务器的磁盘阵列并正确分区
    配置VNC并远程控制服务器(电脑)
    .Net之路(十五)图解LoadRunner压力测试
    Mysql免安装版安装配置及常用操作
  • 原文地址:https://www.cnblogs.com/panther1942/p/13053073.html
Copyright © 2011-2022 走看看