即在應用中誰能證實他就是他本人。通常提供如他們的身份ID 一些標識信息來代表他就是他本人,如提供身份證,用戶名/密碼來證實。java
在 shiro 中,用戶須要提供principals (身份)和credentials(證實)給shiro,從而應用能驗證用戶身份。web
1,principals算法
身份,即主體的標識屬性,能夠是任何東西,如用戶名、郵箱等,惟一便可。spring
一個主體能夠有多個principals,但只有一個Primary principals,通常是用戶名/密碼/手機號。數據庫
2, credentialsapache
證實/憑證,即只有主體知道的安全值,如密碼/數字證書等。json
最多見的principals和credentials組合就是用戶名/密碼了。接下來先進行一個基本的身份認證。安全
一、首先調用Subject.login(token)進行登陸,其會自動委託給Security Manager,調用以前必須經過SecurityUtils. setSecurityManager()設置;cookie
二、SecurityManager負責真正的身份驗證邏輯;它會委託給Authenticator進行身份驗證;app
三、Authenticator纔是真正的身份驗證者,Shiro API中核心的身份認證入口點,此處能夠自定義插入本身的實現;
四、Authenticator可能會委託給相應的AuthenticationStrategy進行多Realm身份驗證,默認ModularRealmAuthenticator會調用AuthenticationStrategy進行多Realm身份驗證;
五、Authenticator 會把相應的token 傳入Realm,從Realm 獲取身份驗證信息,若是沒有返回/拋出異常表示身份驗證失敗了。此處能夠配置多個Realm,將按照相應的順序及策略進行訪問。
Config.java
1 package io.guangsoft.shiro.config; 2
3 import java.util.LinkedHashMap; 4 import java.util.Map; 5
6 import io.guangsoft.shiro.realm.Realm; 7 import org.apache.shiro.authc.credential.HashedCredentialsMatcher; 8 import org.apache.shiro.mgt.RememberMeManager; 9 import org.apache.shiro.mgt.SecurityManager; 10 import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 11 import org.apache.shiro.web.mgt.CookieRememberMeManager; 12 import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 13 import org.apache.shiro.web.servlet.SimpleCookie; 14 import org.springframework.context.annotation.Bean; 15 import org.springframework.context.annotation.Configuration; 16
17 @Configuration 18 public class Config { 19
20 @Bean 21 public Realm realmManager() { 22 // 加密相關
23 HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); 24 // 散列算法
25 hashedCredentialsMatcher.setHashAlgorithmName("md5"); 26 // 散列次數
27 hashedCredentialsMatcher.setHashIterations(2); 28 Realm realm = new Realm(); 29 realm.setCredentialsMatcher(hashedCredentialsMatcher); 30 return realm; 31 } 32
33 @Bean 34 public RememberMeManager rememberMeManager() { 35 CookieRememberMeManager rememberMeManager = new CookieRememberMeManager(); 36 //注入自定義cookie(主要是設置壽命, 默認的一年太長)
37 SimpleCookie simpleCookie = new SimpleCookie(); 38 simpleCookie.setHttpOnly(true); 39 //設置RememberMe的cookie有效期爲7天
40 simpleCookie.setMaxAge(604800); 41 rememberMeManager.setCookie(simpleCookie); 42 return rememberMeManager; 43 } 44
45 @Bean 46 public SecurityManager securityManager() { 47 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 48 securityManager.setRealm(realmManager()); 49 securityManager.setRememberMeManager(rememberMeManager()); 50 return securityManager; 51 } 52
53 @Bean 54 public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { 55 ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 56 shiroFilterFactoryBean.setSecurityManager(securityManager); 57 //當用戶未登陸則跳轉到登陸路徑
58 shiroFilterFactoryBean.setLoginUrl("/login"); 59 //登陸成功後要跳轉的連接,表單登陸方式有效
60 shiroFilterFactoryBean.setSuccessUrl("/index"); 61 //未受權界面,指定沒有權限操做時跳轉頁面
62 shiroFilterFactoryBean.setUnauthorizedUrl("/warning"); 63 //配置不會被過濾的連接順序判斷,過慮器鏈定義,從上向下順序執行,通常將/**放在最下邊
64 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); 65 //對靜態資源設置匿名訪問,anon:全部url均可以匿名訪問
66 filterChainDefinitionMap.put("/assets/**", "anon"); 67 //放開登陸接口,容許進行登陸操做
68 filterChainDefinitionMap.put("/shiro/login", "anon"); 69 //配置退出過濾器,其中的具體的退出代碼Shiro已經替咱們實現了
70 filterChainDefinitionMap.put("/shiro/logout", "logout"); 71 //authc:全部url都必須認證經過才能夠訪問
72 filterChainDefinitionMap.put("/**", "authc"); 73 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); 74 return shiroFilterFactoryBean; 75 } 76
77 }
Realm.java
1 package io.guangsoft.shiro.realm; 2
3 import org.apache.shiro.authc.AuthenticationException; 4 import org.apache.shiro.authc.AuthenticationInfo; 5 import org.apache.shiro.authc.AuthenticationToken; 6 import org.apache.shiro.authc.SimpleAuthenticationInfo; 7 import org.apache.shiro.authz.AuthorizationInfo; 8 import org.apache.shiro.authz.SimpleAuthorizationInfo; 9 import org.apache.shiro.realm.AuthorizingRealm; 10 import org.apache.shiro.subject.PrincipalCollection; 11 import org.apache.shiro.util.ByteSource; 12
13 import java.util.ArrayList; 14 import java.util.List; 15
16 public class Realm extends AuthorizingRealm { 17
18 //認證,模擬從數據庫查詢出密碼
19 @Override 20 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 21 String userName = (String) token.getPrincipal(); 22 String password = "4d521acb9b8b3b4fa082ab16b3bd363a"; 23 String salt = "guanghe"; 24 return new SimpleAuthenticationInfo(userName, password, ByteSource.Util.bytes(salt), this.getName()); 25 }
26 }
ShiroController.java
1 package io.guangsoft.shiro.controller; 2
3 import com.alibaba.fastjson.JSONObject; 4 import org.apache.shiro.SecurityUtils; 5 import org.apache.shiro.authc.*; 6 import org.apache.shiro.subject.Subject; 7 import org.springframework.web.bind.annotation.RequestMapping; 8 import org.springframework.web.bind.annotation.RestController; 9
10 @RestController 11 @RequestMapping("shiro") 12 public class ShiroController { 13
14 @RequestMapping(value = "login") 15 public String login(String username, String password, Boolean rememberMe) { 16 Subject subject = SecurityUtils.getSubject(); 17 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); 18 usernamePasswordToken.setRememberMe(rememberMe); 19 String msg = null; 20 try { 21 subject.login(usernamePasswordToken); 22 msg = "身份認證成功!"; 23 } catch (UnknownAccountException e) { 24 e.printStackTrace(); 25 msg = "帳號不存在!"; 26 } catch (LockedAccountException e) { 27 e.printStackTrace(); 28 msg = "帳號被鎖定!"; 29 } catch (DisabledAccountException e) { 30 e.printStackTrace(); 31 msg = "帳號被禁用!"; 32 } catch (IncorrectCredentialsException e) { 33 e.printStackTrace(); 34 msg = "憑證/密碼錯誤!"; 35 } catch (ExpiredCredentialsException e) { 36 e.printStackTrace(); 37 msg = "憑證/密碼過時!"; 38 } catch (ExcessiveAttemptsException e) { 39 e.printStackTrace(); 40 msg = "登陸失敗次數過多!"; 41 } 42 JSONObject result = new JSONObject(); 43 if(subject.isAuthenticated()) { 44 result.put("code", 0); 45 } else { 46 result.put("code", -1); 47 } 48 result.put("msg", msg); 49 return result.toString(); 50 } 51 }