shiro是java的安全框架,能方便地實現項目的身份驗證、權限驗證等相關安全方面的功能。本人用的shiro版本是1.2.3的,當然還是推薦高版本的,功能封裝得更完善些。
1.用戶注冊時,將用戶設置的密碼加密后存入數據庫中(顯然密碼不能簡單地用md5加密一次或者干脆不加密,這些都是會暴露用戶隱私的,甚至是觸動用戶的利益):
1 //生成鹽(部分,需要存入數據庫中) 2 String random=new SecureRandomNumberGenerator().nextBytes().toHex(); 3 4 //將原始密碼加鹽(上面生成的鹽),並且用md5算法加密三次,將最后結果存入數據庫中 5 String result = new Md5Hash("password",random,3).toString();
2.登錄驗證及權限驗證(繼承AuthorizingRealm,覆蓋其中的方法):
1 @Component 2 public class MyRealM extends AuthorizingRealm { 3 4 5 @Autowired 6 private LoginService loginService; 7 8 /** 9 * 獲取用戶角色和權限,用於權限認證 10 * @param principals 11 * @return 12 */ 13 @Override 14 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 15 16 String username = principals.getPrimaryPrincipal().toString(); 17 18 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); 19 //獲取角色(從數據庫中取出時使用逗號分隔的) 20 UserInfo user = loginService.getUserByName(username); 21 String[] roleArray = user.getUserrole().split(","); 22 23 Set<String> roles = new HashSet<String>(); 24 for (String roleid : roleArray) { 25 roles.add(loginService.getRoles(roleid)); 26 } 27 28 //獲取權限(根據角色查詢權限表) 29 Set<String> permissions = new HashSet<String>(); 30 for (String roleid : roleArray) { 31 permissions.addAll(loginService.getPermissions(roleid)); 32 } 33 34 info.setRoles(roles); 35 info.setStringPermissions(permissions); 36 return info; 37 } 38 39 /** 40 * 設置用戶登錄認證 41 * @param token 42 * @return 43 * @throws AuthenticationException 44 */ 45 @Override 46 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 47 //獲取輸入的用戶賬號,並通過賬號獲取相關信息 48 String username = token.getPrincipal().toString(); 49 UserInfo user = loginService.getUserByName(username); 50 if (user != null) { 51 //將查詢到的用戶賬號和密碼存放到 authenticationInfo用於后面的權限判斷。第三個參數傳入用戶輸入的用戶名。 52 SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPwd(), getName()); 53 //設置鹽,用來核對密碼 54 authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(user.getRandom())); 55 56 return authenticationInfo; 57 } else { 58 return null; 59 } 60 61 } 62 63 64 }
3.shiro增加的配置:
1 <!-- 配置自定義Realm,設定核對密碼時在加鹽后,要用MD5算法對用戶輸入的密碼加密3次用於核對 --> 2 <bean id="myRealM" class="com.test.shiro.MyRealM"> 3 <property name="credentialsMatcher" > 4 <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> 5 <property name="hashAlgorithmName" value="MD5"></property> 6 <property name="hashIterations" value="3"></property> 7 </bean> 8 </property> 9 </bean> 10 11 12 <!-- 安全管理器 --> 13 <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> 14 <property name="realm" ref="myRealM"/> 15 </bean> 16 17 <!--Shiro過濾器--> 18 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 19 <!-- Shiro的核心安全接口,這個屬性是必須的 --> 20 <property name="securityManager" ref="securityManager"/> 21 <!-- 身份認證失敗,則跳轉到登錄頁面的配置 --> 22 <property name="loginUrl" value="/sourceA/pageA"/> 23 <!-- 權限認證失敗,則跳轉到指定頁面 --> 24 <property name="unauthorizedUrl" value="/sourceA/error"/> 25 <!-- Shiro連接約束配置,即過濾鏈的定義 --> 26 <property name="filterChainDefinitions"> 27 <value> 28 <!--anon 表示匿名訪問,不需要認證以及授權 --> 29 /sourceB=anon 30 <!--authc表示需要認證,沒有進行身份認證是不能進行訪問的--> 31 /sourceA*=authc 32 <!--roles[內容] 表示需要內容所示的角色才能訪問該路徑--> 33 /sourceA=roles[user] 34 <!--perms[內容] 表示需要內容所示的權限才能訪問該路徑--> 35 /sourceC/**=perms["sourceC"] 36 /sourceD/**=authc,perms["sourceD"] 37 38 </value> 39 </property> 40 </bean>
4.登錄,調用用戶登錄驗證(權限及角色驗證在用戶訪問某路徑時進行攔截):
1 //用戶信息bean 2 UserInfo info = new UserInfo(); 3 info.setPwd("password"); 4 info.setUsername("username"); 5 6 Subject subject = SecurityUtils.getSubject(); 7 UsernamePasswordToken token = new UsernamePasswordToken(info.getUsername(), info.getPwd()); 8 9 try { 10 11 //驗證 12 subject.login(token); 13 14 //登陸成功后的處理邏輯: 15 System.out.println("登陸成功"); 16 17 } catch (Exception e) { 18 //登陸失敗后的處理邏輯: 19 System.out.println("用戶名或密碼錯誤"); 20 21 }
5.登出
1 Subject subject = SecurityUtils.getSubject(); 2 if (subject.isAuthenticated()) { 3 subject.logout(); 4 }