shiro多系統單點登入
阿新 • • 發佈:2018-12-30
最近做專案遇到了多個系統許可權用的是shiro框架,需要做成單點登入,雖然shiro為單點登入提供了shiro-cas的方案,但是不太符合我們現有專案的框架,現在和大家分享一下我是如何實現單點登入。整體思路是參考cas。
框架圖:
流程介紹
- 使用者第一次訪問系統A
- 登入伺服器判斷當前使用者是否登入如果該使用者登入則重定向到使用者訪問http://redirecturl?sessionid=sessionidg否則調到登入頁面
- 系統A的ssoFilter發現當前session沒有使用者資訊但是有引數sessionid,說明該請求是從單點登入伺服器跳轉過來的並且該使用者是已經登入。在ssoFilter中為response新增addcookie(sessionid),且為response寫入輸出流,該輸出流為一個html頁面其中有一段js程式碼是訪問系統A中使用者訪問的url
- 瀏覽器執行步驟4中返回js,此時訪問系統A時攜帶的cookie中的sessionid是在單點登入系統登入的sessionid,A系統ssoFilter發現該使用者已登入允許訪問本系統資源。
原始碼
- 登入伺服器login.jsp中的一段程式碼
<shiro:authenticated>
<%
String redirectUrl = (String) request.getAttribute("redirectUrl");
if (redirectUrl != null && redirectUrl != "" ) {
response.sendRedirect(redirectUrl+"?SHAREJSESSIONID="+request.getSession().getId());
} else {
response.sendRedirect(request.getContextPath() + "/perm/main/home.do");
}
%>
</shiro:authenticated>
業務系統A中的SSOFilter
public class SSOFilter implements Filter {
private String serverLoginUrl;
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
String reqUrl = httpServletRequest.getScheme() + "://" + httpServletRequest.getServerName() + ":" + httpServletRequest.getServerPort() + httpServletRequest.getContextPath() + httpServletRequest.getRequestURI();
Object username = httpServletRequest.getSession().getAttribute("username");
if (username != null) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
String sid = httpServletRequest.getParameter("SHAREJSESSIONID");
if (StringUtils.isNotEmpty(sid)) {
Cookie cookie = new Cookie("SHAREJSESSIONID", sid);
cookie.setPath("/");
httpServletResponse.addCookie(cookie);
String html = "<html><head><script type=\"text/javascript\">location.href='" + reqUrl + "'</script></head><body></body></html>";
byte[] bytes = html.getBytes();
httpServletResponse.setHeader("Content-Type", "text/html;charset=UTF-8");
httpServletResponse.getOutputStream().write(bytes);
httpServletResponse.getOutputStream().flush();
httpServletResponse.getOutputStream().close();
return;
}
httpServletResponse.sendRedirect(serverLoginUrl + "?redirectUrl=" + reqUrl);
}
public void destroy() {
}
public String getServerLoginUrl() {
return serverLoginUrl;
}
public void setServerLoginUrl(String serverLoginUrl) {
this.serverLoginUrl = serverLoginUrl;
}
}
- 業務系統A中的shiro SSOFilter配置
<!-- Shiro主過濾器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- Shiro的核心安全介面,這個屬性是必須的 -->
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="${permisisonPath}/perm/common/login.do"/>
<property name="unauthorizedUrl" value="${permisisonPath}/perm/common/unauth.do"/>
<property name="filters">
<map>
<entry key="SSO" value-ref="SSOFilter"/>
</map>
</property>
</bean>
<bean id="SSOFilter" class="com.xinhe99.permission.sso.SSOFilter">
<property name="serverLoginUrl" value="${permisisonPath}/perm/common/login.do"/>
</bean>
<!-- 許可權資源配置 -->
<bean id="filterChainDefinitionsService"
class="com.XXXX.XXX.XXXX.shiro.filterchaindefinitions.SimpleFilterChainDefinitionsService">
<property name="definitions">
<value>
/static/**=anon
/需要登入的請求路徑/**=SSO,authc
</value>
</property>
</bean>