安全框架Shiro和SpringSecurity的比較

    兩個基本的概念前端

安全實體:系統須要保護的具體對象數據java

權限:系統相關的功能操做,例如基本的CRUDweb

 Shiro  spring

首先Shiro較之 Spring Security,Shiro在保持強大功能的同時,還在簡單性和靈活性方面擁有巨大優點。數據庫

Shiro是一個強大而靈活的開源安全框架,可以很是清晰的處理認證、受權、管理會話以及密碼加密。以下是它所具備的特色:apache

  1. 易於理解的 Java Security API;
  2. 簡單的身份認證(登陸),支持多種數據源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
  3. 對角色的簡單的籤權(訪問控制),支持細粒度的籤權;
  4. 支持一級緩存,以提高應用程序的性能;
  5. 內置的基於 POJO 企業會話管理,適用於 Web 以及非 Web 的環境;
  6. 異構客戶端會話訪問;
  7. 很是簡單的加密 API;
  8. 不跟任何的框架或者容器捆綁,能夠獨立運行。

Shiro四大核心功能:Authentication,Authorization,Cryptography,Session Management緩存

Shiro架構安全

Shiro三個核心組件:Subject, SecurityManager 和 Realms.架構

Subject:主體,能夠看到主體能夠是任何能夠與應用交互的 「用戶」;app

SecurityManager:至關於 SpringMVC 中的 DispatcherServlet 或者 Struts2 中的 FilterDispatcher;是 Shiro 的心臟;全部具體的交互都經過 SecurityManager 進行控制;它管理着全部 Subject、且負責進行認證和受權、及會話、緩存的管理。

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容器    

相關文章
相關標籤/搜索