Shiro+Cas微服务化及前后端完全分离
本文实例为大家分享了ShiroCas微服务化及前后端完全分离,供大家参考,具体内容如下
shiro+cas微服务化笔记
1.SpringBoot配置
有如下两个配置文件:ShiroBaseConfig.java
importlombok.extern.log4j.Log4j; importorg.apache.shiro.cache.CacheManager; importorg.apache.shiro.cache.MemoryConstrainedCacheManager; importorg.apache.shiro.cas.CasFilter; importorg.apache.shiro.codec.Base64; importorg.apache.shiro.session.mgt.eis.MemorySessionDAO; importorg.apache.shiro.web.mgt.CookieRememberMeManager; importorg.apache.shiro.web.servlet.SimpleCookie; importorg.springframework.beans.factory.annotation.Value; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; /** **Description:shiro权限管理模块conf * *@authorDean.Hwang *@date17/5/18 */ @Configuration @Log4j publicclassShiroBaseConfiguration{ @Value("${cas.server.url.prefix}") privateStringcasPrefix; @Value("${cas.service}") privateStringcasService; /** *会话Cookie模板 * *@return */ @Bean publicSimpleCookiesessionIdCookie(){ SimpleCookiesimpleCookie=newSimpleCookie("sid"); simpleCookie.setHttpOnly(true); simpleCookie.setMaxAge(1800000); returnsimpleCookie; } /** *会话Cookie模板 * *@return */ @Bean publicSimpleCookierememberCookie(){ SimpleCookiesimpleCookie=newSimpleCookie("rememberMe"); simpleCookie.setHttpOnly(true); simpleCookie.setMaxAge(2592000);//30天 returnsimpleCookie; } /** *rememberMe管理器 * *@return */ @Bean publicCookieRememberMeManagerrememberMeManager(SimpleCookierememberCookie){ CookieRememberMeManagercookieRememberMeManager=newCookieRememberMeManager(); cookieRememberMeManager.setCipherKey(Base64.decode(""));//rememberMecookie加密的密钥建议每个项目都不一样默认AES算法密钥长度(128256512位) cookieRememberMeManager.setCookie(rememberCookie); returncookieRememberMeManager; } /** *会话DAO * *@return */ @Bean publicMemorySessionDAOsessionDAO(){ returnnewMemorySessionDAO(); } @Bean publicCacheManagershiroCacheManager(){ returnnewMemoryConstrainedCacheManager(); } @Bean publicKryCasRealmcasRealm(CacheManagershiroCacheManager){ returnnewKryCasRealm(casPrefix,casService,shiroCacheManager); } @Bean publicCasFiltercasFilter(){ CasFiltercasFilter=newCasFilter(); casFilter.setEnabled(true); casFilter.setName("casFilter"); casFilter.setFailureUrl("/authority/casFailure"); returncasFilter; } }
下面ShiroManagerConfiguration.java文件
importorg.apache.shiro.cache.CacheManager; importorg.apache.shiro.cas.CasFilter; importorg.apache.shiro.cas.CasSubjectFactory; importorg.apache.shiro.spring.web.ShiroFilterFactoryBean; importorg.apache.shiro.web.filter.authc.LogoutFilter; importorg.apache.shiro.web.mgt.CookieRememberMeManager; importorg.apache.shiro.web.mgt.DefaultWebSecurityManager; importorg.apache.shiro.web.session.mgt.ServletContainerSessionManager; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.beans.factory.annotation.Value; importorg.springframework.beans.factory.config.MethodInvokingFactoryBean; importorg.springframework.boot.autoconfigure.AutoConfigureAfter; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importjavax.servlet.Filter; importjava.util.HashMap; importjava.util.Map; /** * **Copyright:Copyright(c)2015 *
**
* *@authorDean.Hwang *@date17/5/18 */ @Configuration @AutoConfigureAfter( {ShiroBaseConfiguration.class} ) publicclassShiroManagerConfiguration{ @Autowired privateKryCasRealmkryCasRealm; @Autowired privateCacheManagershiroCacheManager; @Autowired privateCookieRememberMeManagerrememberMeManager; @Value("${cas.server.login.url}") privateStringloginUrl; @Value("${cas.client.url.prefix}") privateStringurlPrefix; @Autowired privateCasFiltercasFilter; @Value("${cas.server.logout.url}") privateStringlogoutUrl; @Value("${cas.client.index.url}") privateStringindexUrl; @Bean publicDefaultWebSecurityManagersecurityManager(){ DefaultWebSecurityManagersecurityManager=newDefaultWebSecurityManager(); securityManager.setRealm(kryCasRealm); securityManager.setSessionManager(newServletContainerSessionManager()); securityManager.setCacheManager(shiroCacheManager); securityManager.setRememberMeManager(rememberMeManager); securityManager.setSubjectFactory(newCasSubjectFactory()); returnsecurityManager; } /** *相当于调用SecurityUtils.setSecurityManager(securityManager) * *@paramsecurityManager *@return */ @Bean publicMethodInvokingFactoryBeanmethodInvokingFactoryBean(DefaultWebSecurityManagersecurityManager){ MethodInvokingFactoryBeanbean=newMethodInvokingFactoryBean(); bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager"); bean.setArguments(newObject[]{securityManager}); returnbean; } @Bean publicShiroFilterFactoryBeanshiroFilter(DefaultWebSecurityManagersecurityManager){ ShiroFilterFactoryBeanfactoryBean=newShiroFilterFactoryBean(); factoryBean.setSecurityManager(securityManager); factoryBean.setLoginUrl(loginUrl+serviceStr+urlPrefix+"/cas"); factoryBean.setSuccessUrl("../mind/index.do"); factoryBean.setUnauthorizedUrl("/unauthorized.jsp"); MapfilterMap=newHashMap<>(); filterMap.put("cas",casFilter); filterMap.put("user",portalUserFilter); //只能在这里初始化LogoutFilter,不然会被springboot注册到/* PortalLogoutFilterlogoutFilter=newPortalLogoutFilter(); logoutFilter.setRedirectUrl(logoutUrl+serviceStr+indexUrl); filterMap.put("logout",logoutFilter); factoryBean.setFilters(filterMap); Map filters=newHashMap<>(); filters.put("/casFailure.jsp","anon"); filters.put("/js/**","anon"); filters.put("/themes/**","anon"); filters.put("/3rdOauth/**","anon"); filters.put("/cas","cas"); filters.put("/logout","logout"); filters.put("/**","user"); factoryBean.setFilterChainDefinitionMap(filters); returnfactoryBean;} }
2.UserFilter的改造
2.1改造的原因:
因为,我们现在新的服务器架构是前后端完全分离的。但是,shiro是不支持完全的前后端分离。所以导致了单点登录完成以后会跳转至接口,而不是目标页面。同时,由于历史原因,我们的cas验证服务器与业务服务器不是同一个域。如果,需要在服务器端进行重定向就必须要通过跨域,考虑到跨域会有风险。所以,我也将sso服务器登录重定向进行了重构。做成了返回json,前端在接收到json自己进行登录页跳转。
具体的实现代码如下:
protectedvoidsaveRequestAndRedirectToLogin(ServletRequestrequest,ServletResponseresponse)throwsIOException{ Sessionsession=SecurityUtils.getSubject().getSession(); if(session!=null){ SavedRequestsavedRequest=newPortalSavedRequest(WebUtils.toHttp(request));//重写的SavedRequest,具体处理由不同的业务需求自定 session.setAttribute(SAVED_REQUEST_KEY,savedRequest); } PrintWriterout=null; try{ ResultVO
此方法是将Cas中的Userfilter进行了重写,并且在配置时使用重写的类对原有的UserFilter进行了覆盖。
#3.登录成功后的重定向:
由于在sso验证服务器登录成功以后会重定向到本地业务服务器上。本地业务服务器验证登录成功以后会默认重定向至配置的SuccessUrl。这样并不能将页面跳转回用户的原来请求的页面。所以我重写了CasFilter中的issueSuccessRedirect达到这个目的
/** **Copyright:Copyright(c)2015 *
* *@authorDean.Hwang *@date17/7/17 */ publicclassPortalCasFilterextendsCasFilter{ @Override protectedvoidissueSuccessRedirect(ServletRequestrequest,ServletResponseresponse)throwsException{ StringsuccessUrl=((ShiroHttpServletRequest)request).getHeader("page-url");//前端页面在请求的时候在header中带上请求这个接口的url。这样便将登录成功后需要跳转的地址绑定到了对应的Subject对象中。以便于在登录以后跳转到这个页面 if(StringUtil.isBlank(successUrl)){ WebUtils.redirectToSavedRequest(request,response,getSuccessUrl()); }else{ WebUtils.redirectToSavedRequest(request,response,successUrl); } } }
#4.用户安全的退出
后期发现直接依靠原有的logout会发生session未注销的情况。所以重写了LogoutFilter。登出的时候直接调用配置的URL即可
/** * **Copyright:Copyright(c)2015 *
* *@authorDean.Hwang *@date17/7/17 */ publicclassPortalLogoutFilterextendsAdviceFilter{ privatestaticfinalLoggerlog=LoggerFactory.getLogger(LogoutFilter.class); publicstaticfinalStringDEFAULT_REDIRECT_URL="/"; privateStringredirectUrl=DEFAULT_REDIRECT_URL; @Override protectedbooleanpreHandle(ServletRequestrequest,ServletResponseresponse)throwsException{ Subjectsubject=getSubject(request,response); StringredirectUrl=getRedirectUrl(request,response,subject); //try/catchaddedforSHIRO-298: try{ subject.logout(); Sessionsession=subject.getSession(); session.stop(); }catch(SessionExceptionise){ log.debug("Encounteredsessionexceptionduringlogout.Thiscangenerallysafelybeignored.",ise); } issueRedirect(request,response,redirectUrl); returnfalse; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。