• 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吨救援拖车
  • 相关阅读:
    Pascal's Triangle II
    Pascal's Triangle
    Best Time to Buy and Sell Stock II
    Best Time to Buy and Sell Stock
    Populating Next Right Pointers in Each Node
    path sum II
    Path Sum
    [转载]小波时频图
    [转载]小波时频图
    [转载]Hilbert变换及谱分析
  • 原文地址:https://www.cnblogs.com/panther1942/p/13053073.html
Copyright © 2020-2023  润新知