本文目錄:
► 第二章:Shiro身份認證
► 2.1 身份認證
► 2.2 環境準備
► 2.3 登錄、退出
下節文章預告
► 第二章:Shiro身份認證(預告)
► 2.4 身份認證流程(預告)
2.1 身份認證
身份驗證,即在應用中誰能證明他就是他本人。一般提供如他們的身份 ID 一些標識信息來表明他就是他本人,如提供身份證,用戶名 / 密碼來證明。
在Shiro中,用戶需要提供principals (身份)和credentials(證明)給 shiro,從而應用能驗證用戶身份:
principals:身份,即主體的標識屬性,可以是任何東西,如用戶名、郵箱等,唯一即可。一個主體可以有多個 principals,但只有一個 Primary principals,一般是用戶名 / 密碼 / 手機號。
credentials:證明 / 憑證,即只有主體知道的安全值,如密碼 / 數字證書等。
另外兩個相關的概念是之前提到的 Subject 及 Realm,分別是主體及驗證主體的數據源。
最常見的 principals 和 credentials 組合就是用戶名 / 密碼了。
接下來先進行一個基本的身份認證。
2.2 環境準備
環境要求:Maven、IDEA
- 新建Maven工程,並且導入以下Jar包依賴 (添加 junit、common-logging 及 shiro-core 依賴、log4j、slfj-api等即可):
<dependencies> <!--Shiro核心包--> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version> </dependency> <!--junit測試包--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!--日誌管理包--> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.12</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.25</version> </dependency> </dependencies>
2.3 登錄、退出
- 準備初始值數據到屬性文件中(shiro.ini)
[users] zhangsan=mima sunwukong=mima
說明:使用 ini 配置文件,通過 [users] 指定了兩個主體:zhang/ mima、sunwukong / mima.
- 添加log4j的日誌輸出格式定義文件log4j.properties
log4j.rootLogger=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n # General Apache libraries log4j.logger.org.apache=WARN # Spring log4j.logger.org.springframework=WARN # Default Shiro logging log4j.logger.org.apache.shiro=TRACE # Disable verbose logging log4j.logger.org.apache.shiro.util.ThreadContext=WARN log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
- 增加測試類,測試主體信息(com.ms.ShiroTest)
- 獲取SecurityManager工廠,此處使用Ini配置文件初始化SecurityManager
- 得到SecurityManager實例 並綁定給SecurityUtils
- 得到Subject及創建用戶名/密碼身份驗證Token(即用戶身份/憑證)
- 登錄,即身份驗證
- 身份驗證成功與否具體信息
- 退出
具體代碼如下:
/** * @Auther: likang * @Description: shiro登錄、退出功能演示 */ public class ShiroTest { public static final Logger logger = LoggerFactory.getLogger(ShiroTest.class); public static void main(String[] args) { //1:獲取SecurityManager工廠,此處使用Ini配置文件初始化SecurityManager Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //2:得到SecurityManager實例 並綁定給SecurityUtils SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); //3:得到Subject及創建用戶名/密碼身份驗證Token(即用戶身份/憑證) Subject subject = SecurityUtils.getSubject(); //4:登錄,即身份驗證 if (!subject.isAuthenticated()){ UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "mima2"); try { subject.login(token); logger.info("登錄成功"); } catch (UnknownAccountException e) { //5:身份驗證失敗 logger.info("用戶名錯誤或者不存在"); } catch (IncorrectCredentialsException e){ logger.info("密碼不匹配"); } catch (LockedAccountException e){ logger.info("用戶已被鎖定,請聯繫管理員"); } catch (DisabledAccountException e){ logger.info("用戶已被禁用,請聯繫管理員"); } catch (ExcessiveAttemptsException e){ logger.info("用戶登錄次數過多"); } catch (AuthenticationException e){ logger.info("用戶登錄失敗,請聯繫管理員"); } } subject.logout();//6:退出 } }
代碼梳理:
- 首先通過 new IniSecurityManagerFactory 並指定一個 ini 配置文件來創建一個 SecurityManager 工廠;
- 接着獲取 SecurityManager 並綁定到 SecurityUtils,這是一個全局設置,設置一次即可;
- 通過 SecurityUtils 得到 Subject,其會自動綁定到當前線程;如果在 web 環境在請求結束時需要解除綁定;然後獲取身份驗證的 Token,如用戶名 / 密碼;
- 調用 subject.login 方法進行登錄,其會自動委託給 SecurityManager.login 方法進行登錄;
- 如果身份驗證失敗請捕獲 AuthenticationException 或其子類,常見的如:
DisabledAccountException(禁用的帳號)、
LockedAccountException(鎖定的帳號)、
UnknownAccountException(錯誤的帳號)、
ExcessiveAttemptsException(登錄失敗次數過多)、
IncorrectCredentialsException (錯誤的憑證)、
ExpiredCredentialsException(過期的憑證)等,
對於頁面的錯誤消息展示,最好使用如 “用戶名 / 密碼錯誤” 而不是 “用戶名錯誤”/“密碼錯誤”,防止一些惡意用戶非法掃描帳號庫;
- 最後可以調用 subject.logout 退出,其會自動委託給 SecurityManager.logout 方法退出。
從如上代碼可總結出身份驗證的步驟:
- 收集用戶身份 / 憑證,即如用戶名 / 密碼;
- 調用 Subject.login 進行登錄,如果失敗將得到相應的 AuthenticationException 異常,根據異常提示用戶錯誤信息;否則登錄成功;
- 最後調用 Subject.logout 進行退出操作。
需要解決的問題?
- 用戶名 / 密碼硬編碼在 ini 配置文件,以後需要改成如數據庫存儲,且密碼需要加密存儲;
- 用戶身份 Token 可能不僅僅是用戶名 / 密碼,也可能還有其他的,如登錄時允許用戶名 / 郵箱 / 手機號同時登錄。
可以留言歡迎討論,如何解決這些問題,答案下期揭曉。