最近在学习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筛一遍,跳转方法会先调用后再访问登录接口;登录后可能不调用跳转方法就通过筛选,直接访问登录接口。这个应该也是重写某个方法可以解决,有空再研究研究源码。