zoukankan      html  css  js  c++  java
  • 安全框架Shiro和SpringSecurity的比较

    来自:https://www.cnblogs.com/zoli/p/11236799.html 

        两个基本的概念

    安全实体:系统需要保护的具体对象数据

    权限:系统相关的功能操作,例如基本的CRUD

     Shiro  

    首先Shiro较之 Spring Security,Shiro在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优势。

    Shiro是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。如下是它所具有的特点:

    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:主体,可以看到主体可以是任何可以与应用交互的 “用户”;

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

  • 相关阅读:
    一句话命令修改大小写
    SpringBoot打成jar包后无法读取resources资源文件里文件路径的问题 cannot be resolved to absolute file path because it does
    java路径两种写法"/"和"\"
    java SASL_SSL 帐号密码 方式访问 kafka
    Mybatis 获得自动生成主键值
    swo2 SOA OAuth 使用,
    java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp是因为时间字段里有'0000-00-00 00:00:00‘这种格式的日期导致的
    OkHttp3找不到FormEncodingBuilder
    Maven依赖的版本范围
    java lambda求和
  • 原文地址:https://www.cnblogs.com/cuiqq/p/12090890.html
Copyright © 2011-2022 走看看