兩個基本的概念前端
安全實體:系統須要保護的具體對象數據java
權限:系統相關的功能操做,例如基本的CRUDweb
Shiro spring
首先Shiro較之 Spring Security,Shiro在保持強大功能的同時,還在簡單性和靈活性方面擁有巨大優點。數據庫
Shiro是一個強大而靈活的開源安全框架,可以很是清晰的處理認證、受權、管理會話以及密碼加密。以下是它所具備的特色:apache
Shiro四大核心功能:Authentication,Authorization,Cryptography,Session Management緩存
Shiro架構安全
Shiro三個核心組件:Subject, SecurityManager 和 Realms.架構
Subject:主體,能夠看到主體能夠是任何能夠與應用交互的 「用戶」;app
Realm:域,Shiro從從Realm獲取安全數據(如用戶、角色、權限),就是說SecurityManager要驗證用戶身份,那麼它須要從Realm獲取相應的用戶進行比較以肯定用戶身份是否合法;也須要從Realm獲得用戶相應的角色/權限進行驗證用戶是否能進行操做;能夠把Realm當作DataSource,即安全數據源。
兩個配置類ShiroConfig和UserRealm
1 package com.example.shirodemo.config; 2 3 import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; 4 import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 5 import org.apache.shiro.web.mgt.DefaultWebSecurityManager; 6 import org.springframework.beans.factory.annotation.Qualifier; 7 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.Configuration; 9 10 import java.util.LinkedHashMap; 11 import java.util.Map; 12 13 /** 14 * shiro配置類 15 */ 16 @Configuration 17 public class ShiroConfig { 18 /** 19 * 建立ShiroFilterFactoryBean 20 */ 21 @Bean 22 public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ 23 ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); 24 //設置安全管理器 25 shiroFilterFactoryBean.setSecurityManager(securityManager); 26 //添加Shiro攔截器 27 /** 28 * Shiro 內置過濾器,能夠實現權限相關的攔截器 29 * anon:無需認證(登陸)能夠直接訪問 30 * authc:必須認證才能訪問 31 * user:若是使用rememberMe的功能才能夠訪問 32 * perms:該資源獲得資源權限才能夠訪問 33 * role:該資源必須獲得角色權限才能夠訪問 34 */ 35 Map<String,String> filterMap=new LinkedHashMap<>(); 36 /* filterMap.put("/add","authc"); 37 filterMap.put("/update","authc");*/ 38 // filterMap.put("/test","anon"); 39 filterMap.put("/login","anon"); 40 //添加Shiro受權攔截器 41 filterMap.put("/add","perms[添加]"); 42 filterMap.put("/foresee","perms[預言將來]"); 43 filterMap.put("/update","perms[修改]"); 44 filterMap.put("/delete","perms[刪除]"); 45 //filterMap.put("/update","perms[]"); 46 //filterMap.put("/delete","perms[]"); 47 //filterMap.put("/getAll","perms[]"); 48 filterMap.put("/*","authc"); 49 //跳轉到登錄的頁面 50 shiroFilterFactoryBean.setLoginUrl("/tologin"); 51 //設置未受權的頁面 52 shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth"); 53 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); 54 55 return shiroFilterFactoryBean; 56 } 57 /** 58 * 建立DefaultWebSecurityManager 59 */ 60 @Bean("securityManager") 61 public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ 62 DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); 63 //關聯Realm 64 securityManager.setRealm(userRealm); 65 return securityManager; 66 } 67 /** 68 * 建立Realm 69 */ 70 @Bean("userRealm") 71 public UserRealm getRealm(){ 72 UserRealm userRealm=new UserRealm(); 73 return userRealm; 74 } 75 /** 76 * 配置shiroDialect,用於thymeleaf和shiro標籤配合使用 77 */ 78 @Bean 79 public ShiroDialect getShiroDialect(){ 80 ShiroDialect shiroDialect=new ShiroDialect(); 81 return shiroDialect; 82 } 83 }
package com.example.shirodemo.config; import com.example.shirodemo.bean.Permission; import com.example.shirodemo.bean.User; import com.example.shirodemo.service.IPermissionService; import com.example.shirodemo.service.IUserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; /** * 自定義Realm */ public class UserRealm extends AuthorizingRealm { @Resource private IUserService userService; @Resource private IPermissionService permissionService; /** * 執行受權邏輯 * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("執行受權邏輯"); /** * 給資源受權 */ SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo(); //添加受權字符串 //simpleAuthorizationInfo.addStringPermission("user:add"); //--------------------認證帳號 Subject subject= SecurityUtils.getSubject(); User user=(User)subject.getPrincipal(); User user1=userService.findById(user.getId()); if(user1==null){ //用戶名不存在 return null; } //-------------------開始受權 List<Permission> permissions =permissionService.getPermissionByUserId(user1.getId()); for (Permission per : permissions) { simpleAuthorizationInfo.addStringPermission(per.getName()); System.out.println("擁有權限:"+per.getName()); } return simpleAuthorizationInfo; } /** * 執行認證邏輯 * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("執行認證邏輯"); /** * 判斷ShiroRealm邏輯UsernamePasswordToken是否正確 */ //1判斷用戶名 UsernamePasswordToken usernamePasswordToken=(UsernamePasswordToken)authenticationToken; User user=userService.findByname(usernamePasswordToken.getUsername()); if(user==null){ //用戶名不存在 return null; } //判斷密碼是否正確 return new SimpleAuthenticationInfo(user,user.getPassword(),""); } }
認證過程
1 /** 2 * 登陸邏輯處理 3 */ 4 @RequestMapping("/login") 5 public String login(User user, Model model) { 6 /** 7 *使用shiro編寫認證操做 8 */ 9 //1:獲取subject 10 Subject subject = SecurityUtils.getSubject(); 11 //2:封裝用戶帳號和密碼 12 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword()); 13 //3:執行登陸方法 14 try { 15 subject.login(usernamePasswordToken); 16 model.addAttribute(user); 17 //登陸成功 18 //成功後跳轉到 19 //return "redirect:/test"; 20 return "/test"; 21 } catch (UnknownAccountException e) { 22 //e.printStackTrace(); 23 //登陸失敗用戶名不存在 24 model.addAttribute("msg","用戶名不存在"); 25 return "login"; 26 }catch (IncorrectCredentialsException e){ 27 //登陸失敗密碼錯誤 28 model.addAttribute("msg","密碼錯誤"); 29 return "login"; 30 } 31 } 32 }
Subject拿到用戶數據後走UserRealm 類裏面的認證邏輯,受權過程比較簡單能夠看你上面的代碼,
Shiro配置攔截器
//添加Shiro攔截器
27 /**
28 * Shiro 內置過濾器,能夠實現權限相關的攔截器
29 * anon:無需認證(登陸)能夠直接訪問
30 * authc:必須認證才能訪問
31 * user:若是使用rememberMe的功能才能夠訪問
32 * perms:該資源獲得資源權限才能夠訪問
33 * role:該資源必須獲得角色權限才能夠訪問
34 */
Spring Security
除了不能脫離Spring,shiro的功能它都有。並且Spring Security對Oauth、OpenID也有支持,Shiro則須要本身手動實現。Spring Security的權限細粒度更高,畢竟Spring Security是Spring家族的。
Spring Security通常流程爲:
①當用戶登陸時,前端將用戶輸入的用戶名、密碼信息傳輸到後臺,後臺用一個類對象將其封裝起來,一般使用的是UsernamePasswordAuthenticationToken這個類。
②程序負責驗證這個類對象。驗證方法是調用Service根據username從數據庫中取用戶信息到實體類的實例中,比較二者的密碼,若是密碼正確就成功登錄,同時把包含着用戶的用戶名、密碼、所具備的權限等信息的類對象放到SecurityContextHolder(安全上下文容器,相似Session)中去。
③用戶訪問一個資源的時候,首先判斷是不是受限資源。若是是的話還要判斷當前是否未登陸,沒有的話就跳到登陸頁面。
④若是用戶已經登陸,訪問一個受限資源的時候,程序要根據url去數據庫中取出該資源所對應的全部能夠訪問的角色,而後拿着當前用戶的全部角色一一對比,判斷用戶是否能夠訪問。
注:
OAuth在"客戶端"與"服務提供商"之間,設置了一個受權層(authorization layer)。"客戶端"不能直接登陸"服務提供商",只能登陸受權層,以此將用戶與客戶端區分開來。"客戶端"登陸受權層所用的令牌(token),與用戶的密碼不一樣。用戶能夠在登陸的時候,指定受權層令牌的權限範圍和有效期。
"客戶端"登陸受權層之後,"服務提供商"根據令牌的權限範圍和有效期,向"客戶端"開放用戶儲存的資料。
OpenID 系統的第一部分是身份驗證,即如何經過 URI 來認證用戶身份。目前的網站都是依靠用戶名和密碼來登陸認證,這就意味着你們在每一個網站都須要註冊用戶名和密碼,即使你使用的是一樣的密碼。若是使用 OpenID ,你的網站地址(URI)就是你的用戶名,而你的密碼安全的存儲在一個 OpenID 服務網站上(你能夠本身創建一個 OpenID 服務網站,也能夠選擇一個可信任的 OpenID 服務網站來完成註冊)。
與OpenID同屬性的身份識別服務商還有ⅥeID,ClaimID,CardSpace,Rapleaf,Trufina ID Card等,其中ⅥeID通用帳戶的應用最爲普遍。
Spring Security和Shiro
相同點:
1:認證功能
2:受權功能
3:加密功能
4:會話管理
5:緩存支持
6:rememberMe功能.......
不一樣點:
優勢:
1:Spring Security基於Spring開發,項目中若是使用Spring做爲基礎,配合Spring Security作權限更加方便,而Shiro須要和Spring進行整合開發
2:Spring Security功能比Shiro更加豐富些,例如安全防禦
3:Spring Security社區資源比Shiro豐富
缺點:
1:Shiro的配置和使用比較簡單,Spring Security上手複雜
2:Shiro依賴性低,不須要任何框架和容器,能夠獨立運行,而Spring Security依賴於Spring容器