简介:
Apache Shiro提供了认证、授权、加密和会话管理功能,将复杂的问题隐藏起来,提供清晰直观的API使开发者可以很轻松地开发自己的程序安全代码。并且在实现此目标时无须依赖第三方的框架、容器或服务,当然也能做到与这些环境的整合,使其在任何环境下都可拿来使用。

Shiro的四大安全基石:

  1. 认证(Authentication):用户身份识别,常被看作"登录",是用户证明自己是谁的一个行为。
  2. 授权(Authorization):访问控制过程,好比决定认证(谁)可以访问什么。
  3. 会话管理(SessionManagement):管理用户的会话(sessions),管理用户与时间相关的状态。
  4. 加密(Cryptography):使用加密算法保护数据更加安全,防止数据被偷窥。

其他附加功能:
Web支持:利用Shiro的web支持API可以很容易地实现web程序安全;
Caching:Caching在Apache Shiro的API中是一等公民,确保安全认证的动作快速而有效。
并发(Concurrency):Apache Shiro支持多线程;
测试(Testing):支持测试,帮助你开发单元和综合测试程序确保你的代码如你所预期的那样进行安全认证。
“Run As”:允许用户使用其他用户身份(如果被允许),这在执行某些管理角本中非常有用。
“Remember Me”:在整个会话周期中(sessions)记住用户的身份,用户只需要在程序强制要求登录的情况下才需要登录。

Shiro的三大核心组件:
**1、Subject:**即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。

**2、SecurityManager:**它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

3、Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的链接细节,并在需要的时候将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和授权,多个也是可以的。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

Shiro的执行流程:

一、实现登录验证

对比传统登录方式:

Shiro实现登录:就相当于shiro帮我们解决认证,授权,加密和密码比较的过程。

整合Shiro:

  1. 添加依赖:
<!--shiro start--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>1.3.2</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.3.2</version></dependency><!--shiro end-->
  1. 配置过滤器:
    相关过滤器有:
    anon: 匿名过滤器,未登陆也可以访问

authc: 认证过滤器, 登陆后访问

perms : 需要xx权限,才能访问

roles: 需要xx角色,才能访问

user: 需要xx用户,才能访问

port:指定端口才能访问

ssl:必须使用https协议才能访问

logout :登出功能

rest :根据指定HTTP请求访问才能访问 ,get方式提交 或者 post方式提交才能访问

配置config类(springboot):

shiro的配置步骤
1 配置安全管理器SecurityManager2 realm域配置:由于SecurityManger需要使用realm域,涉及到用户信息、权限信息,处理用户信息的时候需要加密 3 密码比较器:用户输入的铭文进行加密,并且与数据库中的密文进行比较 4 配置生成过滤器的工厂类
/*** 在ShiroConfig中做什么事情呢?* 1 配置shiro安全管理器,向安全管理器中注入Realm域* 2 配置Realm域:注入密码比较器* 3 配置密码比较器* 4 配置拦截路径和放行路径*/
@Configuration
public class ShiroConfig {/*** 配置安全管理器,并且注入Realm域* @param realm* @return*/@Beanpublic SecurityManager securityManager(Realm realm){DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();securityManager.setRealm(realm);return securityManager;}/***  Credentials:凭证/证书 ---** 配置Realm域,注入密码比较器* @param credentialsMatcher* @return*/@Beanpublic BosRealm realm(CredentialsMatcher credentialsMatcher){BosRealm bosRealm = new BosRealm();//注入密码比较器,比较用户密码是否和数据库一致bosRealm.setCredentialsMatcher(credentialsMatcher);return bosRealm;}/*** 密码比较器** @return*/@Beanpublic CredentialsMatcher credentialsMatcher(){
//    return new HashedCredentialsMatcher("MD5");return new BosCredentialsMatcher();}/*** 配置拦截路径和放行路径* @param securityManager* @return*/@Beanpublic ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){System.out.println("ShiroConfiguration.shirFilter()");// shiro过滤器工厂类ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();// 必须设置 SecurityManagershiroFilterFactoryBean.setSecurityManager(securityManager);//拦截器----Map集合Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了filterChainDefinitionMap.put("/login*", "anon");filterChainDefinitionMap.put("/user/login*", "anon");filterChainDefinitionMap.put("/validatecode.jsp*", "anon");filterChainDefinitionMap.put("/css/**", "anon");filterChainDefinitionMap.put("/js/**", "anon");filterChainDefinitionMap.put("/images/**", "anon");filterChainDefinitionMap.put("/data/**", "anon");//   /** 匹配所有的路径//  通过Map集合组成了一个拦截器链 ,自顶向下过滤,一旦匹配,则不再执行下面的过滤//  如果下面的定义与上面冲突,那按照了谁先定义谁说了算//  /** 一定要配置在最后filterChainDefinitionMap.put("/**", "authc");// 将拦截器链设置到shiro中shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面shiroFilterFactoryBean.setLoginUrl("/login.html");// 登录成功后要跳转的链接shiroFilterFactoryBean.setSuccessUrl("/index.html");//未授权界面;shiroFilterFactoryBean.setUnauthorizedUrl("/403");return shiroFilterFactoryBean;}/*** 开启shiro aop注解支持* 使用代理方式;所以需要开启代码支持* @param securityManager* @return*/@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}/*** 开启cglib代理* @return*/@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();creator.setProxyTargetClass(true);return creator;}}

创建自定义的Realm类:


//自定义Realm ,实现安全数据 连接
public class BosRealm extends AuthorizingRealm {@Resourceprivate UserService userService;@Resourceprivate RoleService roleService;@Resourceprivate PermissionService permissionService;@Overridepublic String getName() {return "bosRealm";}@Override// 认证...protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("shiro 认证管理... ");//1 获得密码String username = (String)token.getPrincipal();//2 通过username从数据库中查找 User对象,如果找到,没找到.User user = userService.findUserByUsername(username);;if(user == null){//返回null表示账号不存在return null;}return new SimpleAuthenticationInfo(user, user.getPassword(), getName());}@Override// 授权...protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {System.out.println("shiro 授权管理...");SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();// 根据当前登录用户 查询对应角色和权限
//    User user = (User) SecurityUtils.getSubject().getPrincipal();User user = (User) pc.getPrimaryPrincipal();// 调用业务层,查询角色List<Role> roles = roleService.findByUser(user);for (Role role : roles) {authorizationInfo.addRole(role.getKeyword());}// 调用业务层,查询权限List<Permission> permissions = permissionService.findByUser(user);for (Permission permission : permissions) {authorizationInfo.addStringPermission(permission.getKeyword());}return authorizationInfo;}
}

编写加密工具类:


public class Encrypt {/** 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,* 常见的散列算法如MD5、SHA等。一般进行散列时最好提供一个salt(盐),比如加密密码“admin”,* 产生的散列值是“21232f297a57a5a743894a0e4a801fc3”,* 可以到一些md5解密网站很容易的通过散列值得到密码“admin”,* 即如果直接对密码进行散列相对来说破解更容易,此时我们可以加一些只有系统知道的干扰数据,* 如用户名和ID(即盐);这样散列的对象是“密码+用户名+ID”,这样生成的散列值相对来说更难破解。*///高强度加密算法,不可逆public static String md5(String password, String salt){return new Md5Hash(password,salt,2).toString();}public static void main(String[] args) {/*** new Md5Hash("123456","lisi",1) :1b539b60601b934441308049a9526e7d* new Md5Hash("123456","lisi",2) :42bd4e7685cb11d3ba02716c313cb04b* new Md5Hash("123456","lisi",3) :16f807d62105b4896034552ee5caeb8a* new Md5Hash("123456","KMNO4",3):8bd35dc14dc07f756478bb44513694f6*///System.out.println(new Md5Hash("123456","KMNO4",3).toString());/*** sha家族加密算法* sha1:aca1eb31d2dcf8f1fcf3fd7a7104232785afad41     40 位* sha256: 616a47d8e1e42f23693bb3a85749bf18d4b6e5380ddfd5717aafa61e33d5211e* sha384:84f5cbb18e2d9f1c81b8cec6f443a2b229993689a2ebae97db37e13af1dfb00ec6168713a53fe19d33a63d4d30889553* sha512:c3e5102b6a7ec6caa5b255dae2895b11c2ef0c7b9bfea8e848653372b53f3ef665d96ea283a21eac683cc0fe5c4b1f64692c2056a8a9636ee1931151043d2b5d*/System.out.println("sha1:"+new Sha1Hash("123456","lisi",2));System.out.println("sha256:"+new Sha256Hash("123456","lisi",2));System.out.println("sha384:"+new Sha384Hash("123456","lisi",2));System.out.println("sha512:"+new Sha512Hash("123456","lisi",2));}
}

编写密码比较器:

public class BosCredentialsMatcher extends SimpleCredentialsMatcher {@Overridepublic boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {//向下转型UsernamePasswordToken upToken = (UsernamePasswordToken)token;//获取用户页面输入的密码String pwd = new String(upToken.getPassword());//加密String newPwd =Encrypt.md5(pwd, upToken.getUsername()).toString();//获取数据库密码String dbPwd = info.getCredentials().toString();return equals(newPwd, dbPwd);}
}

二、实现动态菜单

不同角色看到的菜单是不一样的,买家,品牌商,管理员看到的界面是不同的。

  1. 修改index.html加载基本菜单url路径
// 基本功能菜单加载
$.get("/menu/showMenu",function(data){$.fn.zTree.init($("#treeMenu"), setting, data);
},"json");
  1. 在MenuController添加showMenu方法
@RestController
@RequestMapping("/menu")
public class MenuController {@Autowiredprivate MenuService menuService;// 加载左侧的菜单功能@GetMapping(value = "/showMenu")public ResponseEntity<List<Menu>>  showMenu(){// 调用业务层,查询当前用户具有菜单列表Subject subject = SecurityUtils.getSubject();User user = (User)subject.getPrincipal();// 查询菜单列表List<Menu> result = menuService.findByUser(user);return new ResponseEntity<List<Menu>>(result,HttpStatus.OK);}
}
  1. 编写MenuService的业务层
@Service
@Transactional
public class MenuService {@Autowiredprivate MenuMapper menuMapper;/**查询用户*/public List<Menu> findByUser(User user) {// 针对admin用户显示所有的菜单if(user.getUsername().equals("admin")){return menuMapper.selectAll();}else{// 使用用户ID,查询当前用户具有的菜单列表return menuMapper.findByUser(user.getId());}}
}
  1. 调用DAO
@org.apache.ibatis.annotations.Mapper
public interface MenuMapper extends Mapper<Menu> {@Select("select m.* from t_menu m,t_user u,t_user_role ur,t_role r,t_role_menu rm "+ "where m.id = rm.menu_id and rm.role_id = r.id "+ "and r.id = ur.role_id and ur.user_id = u.id "+ "and u.id=#{id} order by m.priority")List<Menu> findByUser(Integer id);
}

三、细粒度控制方法的权限

对商品的增删查改的方法只能由品牌商这个角色可以调用,通过Shiro提供的若干注解,用于在方法上进行权限控制。


方法注解权限控制:基于代理技术实现
因为我们在前面的shiro的配置类中已经配置了shiro注解框架,使用cglib来创建代理对象,配置shiro aop注解来创建代理,所以这里我们就只要在方法上直接添加以上的注解,就可以实现方法的权限控制了。

无权访问:

Shiro 安全框架相关推荐

  1. Shiro安全框架【快速入门】就这一篇!

    Shiro 简介 照例又去官网扒了扒介绍: Apache Shiro™ is a powerful and easy-to-use Java security framework that perfo ...

  2. 在Spring MVC中使用Apache Shiro安全框架

    我们在这里将对一个集成了Spring MVC+Hibernate+Apache Shiro的项目进行了一个简单说明.这个项目将展示如何在Spring MVC 中使用Apache Shiro来构建我们的 ...

  3. Shiro安全框架的使用

    Shiro安全框架 1.介绍 Shiro有三个核心的概念:Subject.SecurityManager和Realms. Subject(主体): subject本质上是当前正在执行的用户的特定于安全 ...

  4. 大数据WEB阶段 shiro安全控制框架

    shiro安全框架 零.目录 问题引申 shiro介绍 shiro工作流程 使用shiro 进行登录操作 使用shiro进行权限管理 一. 问题引申 需要实现的功能: 用户没有登录的情况下 , 处理登 ...

  5. java权限框架_Java高级工程师必备技术栈-由浅入深掌握Shiro权限框架

    权限系统在任何一个系统中都存在,随着分布式系统的大行其道,权限系统也趋向服务化,对于一个高级工程师来说,权限系统的设计是必不可少需要掌握的技术栈 Apache Shiro™是一个功能强大且易于使用的J ...

  6. shiro subject.getprincipal()为null_(变强、变秃)Java从零开始之Shiro安全框架

    Shiro安全框架 一.Shiro简介 二.Shiro架构图 三.Shiro涉及常见名词 四.Shiro配置文件详解 shiro.ini 文件放在 classpath 下 ,shiro 会自动查找.其 ...

  7. thymeleaf模板引擎shiro集成框架

    shiro权限框架.前端验证jsp设计.间tag它只能用于jsp系列模板引擎. 使用最近项目thymeleaf作为前端模板引擎,采用HTML档,未出台shiro的tag lib,假设你想利用这段时间s ...

  8. (转) shiro权限框架详解06-shiro与web项目整合(上)

    http://blog.csdn.net/facekbook/article/details/54947730 shiro和web项目整合,实现类似真实项目的应用 本文中使用的项目架构是springM ...

  9. 视频教程-Apache Shiro权限框架实战+项目案例视频课程-Java

    Apache Shiro权限框架实战+项目案例视频课程 拥有10余年项目实战经验. 2006-2011在nttdata从事对日软件开发类工作. 2011-2015在HP从事技术服务工作. 擅长于j2e ...

最新文章

  1. pandas中的基本功能
  2. dubbo2.5-spring4-mybastis3.2-springmvc4-mongodb3.4-redis3(十)之Spring MVC中使用 Swagger2 构建Restful API...
  3. IBM 声明对 Google 违背承诺未将 Istio 贡献给 CNCF 表示失望
  4. Java Web学习笔记09:文件上传与下载
  5. android菜单详解四:子菜单
  6. 如何才能写出“高质量”的代码?
  7. network 宽带比特b,字节B
  8. Atititt hi dev eff db op Spring JDBC 目录 1. Spring JDBC 2 1 1.1. Atitit 数据库db insert 插入数据data 最佳实践
  9. EasyClick 调用javaMD5加密
  10. sas不能安装独立的java_SAS安装问题解决办法
  11. 李白关于鸿蒙的诗,名诗欣赏:李白《把酒问月》之--青天有月来几时
  12. ae导出html,动画还原100%-AE一键导出
  13. Myshell AI:让你轻松提高英语口语和听力的神器
  14. 同一个网段win10远程linux,Win10专业版系统在局域网内远程另外一台电脑教程
  15. 利用DFS解决太平洋大西洋水流问题
  16. 海盗分金-动态规划实现
  17. 【15.罗马数字转整数】
  18. modbus tcp主站和从站_组态王与西门子 PLC无线Modbus通讯
  19. 2017河南工业大学校赛 C 魔法宝石
  20. 如何在 Ubuntu 20.04 / KylinOS-V10-SP1 上安装 Sublime Text 4

热门文章

  1. 排版侠html怎么复制,排版侠微信编辑器使用方法教程
  2. arcgis绘核密度分布图
  3. 【理财入门一】三大资产与财务自由
  4. 稳定、易用、不掉线,家用NAS终极体验,铁威马F4-421上手
  5. 怎么判断机械表上满弦_机械手表上弦是什么意思,怎么看手表有没有上满弦
  6. php保存微信头像,保存访问者微信头像至服务器
  7. 雨林木风linux安装教程,雨林木风修复win7系统虚拟机安装linux提示network error的办法...
  8. 华为路由器怎么看是不是公网_华为路由器怎么判断有没有被蹭网
  9. 键盘移动小div(js原生)
  10. 基于ResNet50网络的简单垃圾分类网络