最近在做一个ssm项目,不由得思考上述问题。 首先介绍两个基本的概念: 安全实体:系统需要保护的具体对象数据 权限:系统相关的功能操作,例如基本的CRUD ## Shiro简介 Apache Shiro是一个强大而灵活的开源安全框架,它能够干净利落地处理身份认证,授权,企业会话管理和加密。 Shiro较之 Spring Security,Shiro在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优势。 以下是你可以用Apache Shiro所做的事情: 1. 验证用户 2. 对用户访问进行控制如判断用户是否拥有角色admin。判断用户是否拥有访问的权限 3. 在任何环境下使用 Session API。例如CS程序。 4. 可以使用多个用户数据源。例如一个是oracle用户库,另外一个是mysql用户库。,shiro官方建议开启。 5. 单点登录(SSO)功能。 6. “Remember Me”服务 ,类似购物车的功能,shiro官方建议开启。 ### Shiro四大核心功能:Authentication, Authorization, Cryptography, Session Management  ### Shiro三个核心组件:Subject, SecurityManager 和 Realms. 1. ****Subject:****主体,可以看到主体可以是任何可以与应用交互的 “用户”; 2. ****SecurityManager:****相当于 SpringMVC 中的 DispatcherServlet 或者 Struts2 中的 FilterDispatcher;是 Shiro 的心脏;所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进行认证和授权、及会话、缓存的管理。 3. ****Realm:****域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。 ****两个配置类ShiroConfig和UserRealm **** package com.example.shirodemo.config; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map; /** * shiro配置类 */ @Configuration public class ShiroConfig { /** * 创建ShiroFilterFactoryBean */ @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); //设置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); //添加Shiro拦截器 /** * Shiro 内置过滤器,可以实现权限相关的拦截器 * anon:无需认证(登录)可以直接访问 * authc:必须认证才能访问 * user:如果使用rememberMe的功能才可以访问 * perms:该资源得到资源权限才可以访问 * role:该资源必须得到角色权限才可以访问 */ Map filterMap=new LinkedHashMap<>(); /* filterMap.put("/add","authc"); filterMap.put("/update","authc");*/ // filterMap.put("/test","anon"); filterMap.put("/login","anon"); //添加Shiro授权拦截器 filterMap.put("/add","perms[添加]"); filterMap.put("/foresee","perms[预言未来]"); filterMap.put("/update","perms[修改]"); filterMap.put("/delete","perms[删除]"); //filterMap.put("/update","perms[]"); //filterMap.put("/delete","perms[]"); //filterMap.put("/getAll","perms[]"); filterMap.put("/*","authc"); //跳转到登陆的页面 shiroFilterFactoryBean.setLoginUrl("/tologin"); //设置未授权的页面 shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap); return shiroFilterFactoryBean; } /** * 创建DefaultWebSecurityManager */ @Bean("securityManager") public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager(); //关联Realm securityManager.setRealm(userRealm); return securityManager; } /** * 创建Realm */ @Bean("userRealm") public UserRealm getRealm(){ UserRealm userRealm=new UserRealm(); return userRealm; } /** * 配置shiroDialect,用于thymeleaf和shiro标签配合使用 */ @Bean public ShiroDialect getShiroDialect(){ ShiroDialect shiroDialect=new ShiroDialect(); return shiroDialect; } } 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 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(),""); } } ****认证过程**** /** * 登录逻辑处理 */ @RequestMapping("/login") public String login(User user, Model model) { /** *使用shiro编写认证操作 */ //1:获取subject Subject subject = SecurityUtils.getSubject(); //2:封装用户账号和密码 UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getUsername(), user.getPassword()); //3:执行登录方法 try { subject.login(usernamePasswordToken); model.addAttribute(user); //登录成功 //成功后跳转到 //return "redirect:/test"; return "/test"; } catch (UnknownAccountException e) { //e.printStackTrace(); //登录失败用户名不存在 model.addAttribute("msg","用户名不存在"); return "login"; }catch (IncorrectCredentialsException e){ //登录失败密码错误 model.addAttribute("msg","密码错误"); return "login"; } } } Subject拿到用户数据后进入UserRealm 类里面的认证逻辑,授权过程比较简单可以参考上述代码 ****Shiro配置拦截器**** //添加Shiro拦截器 /** * Shiro 内置过滤器,可以实现权限相关的拦截器 * anon:无需认证(登录)可以直接访问 * authc:必须认证才能访问 * user:如果使用rememberMe的功能才可以访问 * perms:该资源得到资源权限才可以访问 * role:该资源必须得到角色权限才可以访问 */ ## 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容器 最后修改:2020 年 07 月 05 日 08 : 06 PM © 著作权归作者所有 赞赏 如果觉得我的文章对你有用,请随意赞赏 ×Close 赞赏作者 扫一扫支付 支付宝支付 微信支付