专栏首页Java编程指南安全框架Shiro和SpringSecurity的比较

安全框架Shiro和SpringSecurity的比较

两个基本的概念

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

权限:系统相关的功能操作,例如基本的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;23 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;910 import java.util.LinkedHashMap;11 import java.util.Map;1213 /**14  * shiro配置类15  */16 @Configuration17 public class ShiroConfig {18     /**19      * 创建ShiroFilterFactoryBean20      */21     @Bean22     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);5455         return shiroFilterFactoryBean;56     }57     /**58      * 创建DefaultWebSecurityManager59      */60     @Bean("securityManager")61     public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){62         DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();63         //关联Realm64         securityManager.setRealm(userRealm);65         return securityManager;66     }67     /**68      * 创建Realm69      */70     @Bean("userRealm")71     public UserRealm getRealm(){72         UserRealm userRealm=new UserRealm();73         return userRealm;74     }75     /**76      * 配置shiroDialect,用于thymeleaf和shiro标签配合使用77      */78     @Bean79     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 {    @Resourceprivate IUserService userService;    @Resourceprivate 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:获取subject10         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容器

本文分享自微信公众号 - Java编程指南(JavaXxzyfx),作者:Java编程指南

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-05-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 你真的会用Java io流吗?

    Java中I/O操作主要是指使用Java进行输入,输出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列。...

    Java编程指南
  • 使用java进行excel读取和写入

    4:在D盘下面创建readExcel.xls(有内容) 和writeExcel.xlsx即可

    Java编程指南
  • 只知道用是不行的!浅析pagehelper分页原理

    之前项目一直使用的是普元框架,最近公司项目搭建了新框架,主要是由公司的大佬搭建的,以springboot为基础。为了多学习点东西,我也模仿他搭了一套自己的框架,...

    Java编程指南
  • Excel公式技巧56:获取最大值/最小值所在的单元格地址

    在《Excel公式技巧54:在多个工作表中查找最大值最小值》中,我们在MAX/MIN函数中使用多工作表引用来获取最大值/最小值。在《Excel公式技巧55:查找...

    fanjy
  • Stage3d AGAL GPU处理照片 旧照片效果 sepia || pixelbender

    用户1258909
  • Linux 常用脚本

    用户1180017
  • 初始化数据库和导入数据

    在Spring Boot应用的测试一文中,我们在StarterRunner类的run(...)方法中给数据库中添加一些初始数据。尽管通过编程方式添加初始数据比较...

    阿杜
  • 零基础大数据学习框架

    大数据开发最核心的课程就是Hadoop框架,几乎可以说Hadoop就是大数据开发。这个框架就类似于Java应用开发的SSH/SSM框架,都是Apache基金会或...

    一起学习大数据
  • Linux上开机自动运行jar

    剑行者
  • Leetcode 763. Partition Labels

    版权声明:博客文章都是作者辛苦整理的,转载请注明出处,谢谢! https://blog.cs...

    Tyan

扫码关注云+社区

领取腾讯云代金券