登錄
原理
使用** FormAuthenticationFilter**過濾器實現(xiàn), 原理如下:
用戶沒有認(rèn)證時, 就會請求 loginurl進(jìn)行認(rèn)證, 用戶身份和用戶密碼提交數(shù)據(jù)到loginurl地址.
數(shù)據(jù)提交到 loginurl 地址后, 由** FormAuthenticationFilter**進(jìn)行攔截, 并取出 request 中的username 和 password.
然后** FormAuthenticationFilter** 會調(diào)用 realm, 在進(jìn)行調(diào)用時會傳入一個 token, 也就是會傳入username 和 password.
最后 realm 認(rèn)真時根據(jù) username 查詢用戶信息.例如我們之前查詢了用戶菜單和 url.
如果查詢不到, realm 返回 null, ** FormAuthenticationFilter**向 request 域填充一個參數(shù), 這個參數(shù)記錄了異常信息.
實現(xiàn)
//登陸提交地址,和applicationContext-shiro.xml中配置的loginurl一致
@RequestMapping("login")
public String login(HttpServletRequest request)throws Exception{
//如果登陸失敗從request中獲取認(rèn)證異常信息,shiroLoginFailure就是shiro異常類的全限定名
String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
//根據(jù)shiro返回的異常類路徑判斷,拋出指定異常信息
if(exceptionClassName!=null){
if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
//最終會拋給異常處理器
throw new CustomException("賬號不存在");
} else if (IncorrectCredentialsException.class.getName().equals(
exceptionClassName)) {
throw new CustomException("用戶名/密碼錯誤");
} else if("randomCodeError".equals(exceptionClassName)){
throw new CustomException("驗證碼錯誤 ");
}else {
throw new Exception();//最終在異常處理器生成未知錯誤
}
}
//此方法不處理登陸成功(認(rèn)證成功),shiro認(rèn)證成功會自動跳轉(zhuǎn)到上一個請求路徑
//登陸失敗還到login頁面
return "login";
}
這里一定要注意我們寫的這個
login()方法, 只是負(fù)責(zé)處理認(rèn)證失敗的結(jié)果, 如果用戶認(rèn)證成功那么就會跳轉(zhuǎn)到上一個請求路徑.
什么是上一個請求路徑呢?
答: 如果你要訪問 xxxx.jsp 但是 shiro 發(fā)現(xiàn)你還沒有登錄, 就會進(jìn)行攔截, 并跳轉(zhuǎn)到登錄界面例如login.jsp, 當(dāng)認(rèn)證成功后會跳轉(zhuǎn)到xxxx.jsp
認(rèn)證攔截過濾器配置
<!-- 對靜態(tài)資源設(shè)置匿名訪問 -->
/images/** = anon
/js/** = anon
/styles/** = anon
<!-- /** = authc 所有url都必須認(rèn)證通過才可以訪問-->
/** = authc
退出
不用我們實現(xiàn)退出, 只要訪問一個退出 url, 由LogoutFilter攔截住, 清除 session.
<!-- 請求 logout.action地址,shiro去清除session-->
/logout.action = logout
從 Shiro 的 session 中獲取認(rèn)證信息
//因為我們用過 Shiro 用戶認(rèn)證后是存放在 Shiro 的 session 中.
Subject subject = SecurityUtils.getSubject();
//取出身份信息
subject.getPrincipal();
