spring boot+shiro整合学习过程碰到的问题

最近在学习spring boot整合shiro实现登录和权限的功能,找到一个程序媛博主写的还不错,贴上链接:https://www.jianshu.com/p/672abf94a857

然后在学习过程中发现了一些问题,自己摸索着解决了,写篇博客记录下,整合主要实现在上面链接。

1.登录成功后跳转页面问题

参考博客实现完所有的配置后,按照我最初的印象,shiro设置了successUrl,例如

shiroFilterFactoryBean.setSuccessUrl("/index");

那么登录成功后就会跳转到/index对应页面,然而登录接口认证成功,页面没有跳转,反复尝试,后来发现参考博客是在前端js直接

location.href = "/index";

不怎么写前端,所以遗漏前端问题,跑通后就明白了,因为她是前后端分离,后端接口只需返回json串,登录页面跳转都由前端控制。接下来我就开始钻牛角尖了,非要用shiro框架实现跳转,去掉前端跳转,后端接口也要修改。从shiro框架入手:

  //配置过滤器
    @Bean(name="shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        shiroFilterFactoryBean.setLoginUrl("/login");//登录连接
        shiroFilterFactoryBean.setSuccessUrl("/index");//登录成功后跳转连接,需重写filter
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");//未授权跳转url
//        Map map = new LinkedHashMap();
//        map.put("authc",new MyFormAuthenticationFilter());
//        shiroFilterFactoryBean.setFilters(map);
        // 定义shiro过滤链
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();

        // <!-- 过滤链定义,从上向下顺序执行,/**放在最下面,过滤链的最后一关,表示除去以上各环节,剩余url的都需要验证 -->
        // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->
        filterChainDefinitionMap.put("/static/**", "anon");
        filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/css/**","anon");
        filterChainDefinitionMap.put("/register","anon");
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/index", "anon");//首页
        filterChainDefinitionMap.put("/login", "authc");//登录接口经过filter筛一遍
//        filterChainDefinitionMap.put("/login", "anon");//跳转登录页面
//        filterChainDefinitionMap.put("/ajaxLogin", "anon");//开放登录接口
        //上两个/login和/ajaxLogin,前后端分离使用,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
        //不使用,shiro控制跳转页面,默认跳转到之前请求页面,跳转successUrl需重写filter
        filterChainDefinitionMap.put("/**","authc");
        filterChainDefinitionMap.put("/logout","logout");//配置退出
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        System.out.println("Shiro拦截器工厂类注入成功");
        return shiroFilterFactoryBean;
    }

注释掉原来的/login和/ajaxLogin配置,登录接口改为与loginUrl同名,并且交给authc过滤器管理。这样就实现了shiro框架控制登录跳转。解释下操作,我调试源码发现,shiro框架登录后跳转页面是在authc过滤链中实现的,所以要把登录接口交给authc过滤器管理,然而不登陆又没有权限访问authc过滤器管理的接口,改为与loginUrl就可以了,主要在FormAuthenticationFilter中的onAccessDenied方法中判断是否有访问权限。

2.shiro登录后默认跳转上一次访问url,设置的successUrl不生效问题

如题,第一个问题解决了,发现还是不跳转设置好的successUrl,参考别的博客,是shiro框架默认跳转上一次访问url,查看了源码发现,登录成功后调用FormAuthenticationFilter中的onLoginSuccess,源码如下:

protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
    return true;
}

根本没用上successUrl啊!怪不得无效,所以写一个MyFormAuthenticationFilter继承FormAuthenticationFilter,重写onLoginSuccess:

    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        WebUtils.issueRedirect(request,response,getSuccessUrl(), null, true);
        return false;
    }

写完MyFormAuthenticationFilter还要使用,加入到过滤链中,就是第一个问题中注释掉的:

Map map = new LinkedHashMap();
map.put("authc",new MyFormAuthenticationFilter());
shiroFilterFactoryBean.setFilters(map);

authc过滤器具体实现改为MyFormAuthenticationFilter,这样successUrl就生效了,主要应用场景应该为登录成功后只跳转到指定url。还有提醒一句,shiro框架控制登录跳转返回的是一个页面,查看源码发现是调用WebUtils.issueRedirect方法,

public static void issueRedirect(ServletRequest request, ServletResponse response, String url, Map queryParams, boolean contextRelative, boolean http10Compatible) throws IOException {
    RedirectView view = new RedirectView(url, contextRelative, http10Compatible);
    view.renderMergedOutputModel(queryParams, toHttp(request), toHttp(response));
}

我之前用ajax调用登录接口,就不知道怎么处理view,后来直接用原生js就可以了(不怎么写前端,以后努力向全栈学习!)

3.待解决问题

shiro重复登录:如果使用shiro框架自己跳转页面,只有第一次登录成功后正常跳转,第二次登录url直接访问登录接口了,因为登录接口由authc过滤器管理,登录前需要经过authc筛一遍,跳转方法会先调用后再访问登录接口;登录后可能不调用跳转方法就通过筛选,直接访问登录接口。这个应该也是重写某个方法可以解决,有空再研究研究源码。

猜你喜欢

转载自blog.csdn.net/qq_29856253/article/details/86569608