Shiro的Filter神奇的失效了

avatar

问题描述

最近做项目用到了Shiro,但是今天不知道怎么回事突然失效了,拦截器没发挥作用。 下面是我的代码

  1. ShiroConfig

@Configuration
class ShiroConfig {
    @Bean
    AuthRealm authRealm(UserService userService, RoleService roleService) {
        return new AuthRealm(userService, roleService)
    }
    //权限管理,配置主要是Realm的管理认证
    @Bean("securityManager")
     SecurityManager securityManager(AuthRealm authRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(authRealm);
        return securityManager;
    }

    @Bean
     ShiroFilterFactoryBean shiroFilter(AuthRealm authRealm) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager(authRealm));

        Map<String, Filter> filters = new HashMap<>();
        filters.put("auth", new BasicHttpAuthenticationFilter() {

            @Override
            protected boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
                HttpServletRequest req = (HttpServletRequest) request;
                String authorization = req.getHeader("token");
                return authorization != null;
            }


            @Override
            protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {

                if (isLoginAttempt(request, response)) {

                    try {
                        executeLogin(request, response);
                        return true;

                    } catch (Exception e) {
                        return false;
                    }


                } else {
                    return false;
                }
            }

            /**
             * 这里重写了父类的方法,使用我们自己定义的Token类,提交给shiro。这个方法返回null的话会直接抛出异常,进入isAccessAllowed()的异常处理逻辑。
             */
            @Override
            protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) {
                return new JWTToken(((HttpServletRequest) servletRequest).getHeader("token"));

            }

            /**
             * 如果这个Filter在之前isAccessAllowed()方法中返回false,则会进入这个方法。我们这里直接返回错误的response
             */
            @Override
            protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
                HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse);
                httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8");
                servletResponse.getWriter().write(R.error(0, "Token异常,请检查是否存在或过期!").toString());
                servletResponse.getWriter().flush();
                return false;
            }

            /**
             * 如果Shiro Login认证成功,会进入该方法,等同于用户名密码登录成功,我们这里还判断了是否要刷新Token
             */

            @Override
            protected boolean executeLogin(ServletRequest request, ServletResponse servletResponse) throws AuthenticationException {
                HttpServletRequest httpServletRequest = (HttpServletRequest) request;
                JWTToken token = new JWTToken(httpServletRequest.getHeader("token"));
                getSubject(request, servletResponse).login(token);
                return true;


            }

            /**
             * 提供跨域支持
             */
            @Override
            protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
                HttpServletRequest httpServletRequest = (HttpServletRequest) request;
                HttpServletResponse httpServletResponse = (HttpServletResponse) response;
                httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
                httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
                httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
                return true;
            }

        });
        shiroFilter.setFilters(filters);
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/**", "auth")
        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }

    //加入注解的使用,不加入这个注解不生效
    @Bean
    AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    SessionStorageEvaluator sessionStorageEvaluator() {
        DefaultWebSessionStorageEvaluator sessionStorageEvaluator = new DefaultWebSessionStorageEvaluator();
        sessionStorageEvaluator.setSessionStorageEnabled(false);
        return sessionStorageEvaluator;
    }
}

  1. AuthRealm
class AuthRealm extends AuthorizingRealm {

    private UserService userService
    private RoleService roleService

    AuthRealm(UserService userService, RoleService roleService) {
        this.userService = userService
        this.roleService = roleService
    }
/**
 * 这里是添加角色和权限的接口,
 * @param principalCollection
 * @return
 */
    @Override
    @Transactional

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo()
        AppUser appUser = userService.findByPrinciple(principalCollection.getPrimaryPrincipal() as String)
        for (Role role : roleService.getByUser(appUser)) {
            //添加角色
            simpleAuthorizationInfo.addRole(role.getName())
//            for (Permission permission:role.getPermissions()) {
//                //添加权限
//                simpleAuthorizationInfo.addStringPermission(permission.getPermission());
//            }
        }
        return simpleAuthorizationInfo
    }
    /**
     * 必须重写此方法,不然会报错
     */
    @Override
    boolean supports(AuthenticationToken token) {
        return token instanceof JWTToken
    }

    /**
     * 这里是获取认证信息的接口,其实就是登陆以后验证数据库的密码是否匹配
     * @param authenticationToken
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        String token = (String) authenticationToken.getCredentials()
        try {
            Map<String, Object> map = JwtUtils.getMap(token)
            if (map.containsKey("principle")) {
                String principle = map.get("principle") as String
                if (principle) {
                    AppUser appUser = userService.findByPrinciple(principle)
                    if (!appUser) {
                        throw new XException("用户不存在!")
                    }

                    return new SimpleAuthenticationInfo(principle, authenticationToken.getCredentials(), "BASE_REALM")
                }
            }
            throw new XException(500, "请求token不合法")

        } catch (e) {
            //e.printStackTrace()
            throw new XException(500, "请求token不合法")
        }


    }
}
  1. ShiroAuthFilter

class ShiroAuthFilter extends BasicHttpAuthenticationFilter {
    @Override
    protected void postHandle(ServletRequest request, ServletResponse response) throws Exception {
        super.postHandle(request, response)
        println("拦截器开始作用")
    }

/**
 * 判断用户是否想要登入。
 * 检测header里面是否包含Authorization字段即可
 */
    //@Override
    boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
        println("isLoginAttempt拦截器开始作用")

        HttpServletRequest req = (HttpServletRequest) request
        String authorization = req.getHeader("token")
        return authorization != null
    }

    /**
     * 父类会在请求进入拦截器后调用该方法,返回true则继续,返回false则会调用onAccessDenied()。
     * 这里在不通过时,还调用了isPermissive()方法,我们后面解释。
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        println("isAccessAllowed")

        if (isLoginAttempt(request, response)) {
            try {
                executeLogin(request, response)
                return true
            } catch (e) {
                throw new XException(0, e.message)
                //false
            }

        } else {
            return false
        }
    }

/**
 * 这里重写了父类的方法,使用我们自己定义的Token类,提交给shiro。这个方法返回null的话会直接抛出异常,进入isAccessAllowed()的异常处理逻辑。
 */
    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) {
        new JWTToken((servletRequest as HttpServletRequest).getHeader("token"))
    }
    /**
     * 如果这个Filter在之前isAccessAllowed()方法中返回false,则会进入这个方法。我们这里直接返回错误的response
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        println("onAccessDenied")

        HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse)
        httpServletResponse.setHeader("Content-Type", "application/json;charset=utf-8")
        servletResponse.getWriter().write(R.error(0, "请求失败,缺少Token!").toJSONString())
        servletResponse.getWriter().flush()

        return false
    }
    /**
     *  如果Shiro Login认证成功,会进入该方法,等同于用户名密码登录成功,我们这里还判断了是否要刷新Token
     */

    @Override
    protected boolean executeLogin(ServletRequest request, ServletResponse servletResponse) {
        println("executeLogin")

        HttpServletRequest httpServletRequest = (HttpServletRequest) request
        JWTToken token = new JWTToken(httpServletRequest.getHeader("token"))
        try {
            getSubject(request, servletResponse).login(token)
            return true

        } catch (e) {
            e.printStackTrace()
            return false
        }

    }

/**
 * 提供跨域支持
 */
    @Override
    protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request
        HttpServletResponse httpServletResponse = (HttpServletResponse) response
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"))
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE")
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"))
        // 跨域时会首先发送一个option请求,这里我们给option请求直接返回正常状态
//        if (httpServletRequest.getMethod() == RequestMethod.OPTIONS.name()) {
//            httpServletResponse.setStatus(HttpStatus.OK.value())
//            return false
//        } else {
//            return true
//        }
        return true
    }
}

希望各位大佬帮忙看看!

目前还没有回答,快来帮帮TA吧!
添加一条评论 请尽量发布对他人有帮助的评论

登录后可发布评论

登录 | Github登录