luckyxl0 2019-06-29
Apache Shiro是Java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。
Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE环境,也可以用在JavaEE环境。Shiro可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存等,在此我仅仅介绍我们公司使用的认证、授权、加密功能,对于其他功能,小伙伴可以发挥一下自学能力呦
身份认证/登录,验证用户是不是拥有相应的身份;
授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者;
相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理
域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
token相当于一个令牌,是将用户的一些信息(如账号、密码、等)经过散列然后生成一个无意义的字符串保存在数据库或者redis,散列不可逆,用户登录时只能通过重新散列然后得到串和数据库中的串做比较,看是否相同判定账号密码是否正确
相信看完上面的工作流程图大家一定会产生一个疑问-->为什么要realm?请看下文分析。。。。
shiro作为一个安全授权框架,对于用户安全登录上,怎样的用户是安全的?怎怎样的用户是可以进入的?样的用户该拥有什么样的权限?相信这些只有开发者才知道,realm正是shiro留给开发者用于自定义用户登录验证和授权认证的一个类,我们可以通过实现Realm接口创建一个自定义的realm类,用于自定义用户登录验证方式(AuthenticationInfo来完成)和授权验证(AuthorizationInfo来完成)
相信大家通过上面的讲解对shiro已经有了一些基本的了解,那么接下来我将通过我们公司封装的shiro框架为例,向大家揭秘登录和授权功能
通过查看代码,我们知道这个token来自于请求域,来自于用户填写的信息
boolean loginSuccess = this.login(new Token(token));
将获得的token传入到一个login方法中,接下来让我们顺着这里往下走,来到了另一个login,里面有这么一句-->subject.login(token);
在这个方法里面我们可以发现这么一句-->info = authenticate(token);,我们可以发现这就是在间接地调用relam类里面的我们自动以的验证方法
我们会发现他是通过用户数据为key在redis中尝试获取有没有对应的value,来证明是否这个用户曾经注册过,或者账号密码和一些信息是否正确
主体,即访问应用的用户,在Shiro中使用Subject代表该用户。用户只有授权后才允许访问相应的资源。
在应用中用户可以访问的任何东西,比如访问JSP页面、查看/编辑某些数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。
安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:
访问用户列表页面
查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控制)
打印文档等等。。。
如上可以看出,权限代表了用户有没有操作某个资源的权利,即反映在某个资源上的操作允不允许,不反映谁去执行这个操作。所以后续还需要把权限赋予给用户,即定义哪个用户允许在某个资源上做什么操作(权限),Shiro不会去做这件事情,而是由实现人员提供。
Shiro支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限,即实例级别的),后续部分介绍。
角色代表了操作集合,可以理解为权限的集合,一般情况下我们会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等都是角色,不同的角色拥有一组不同的权限。
即直接通过角色来验证用户有没有操作权限,如在应用中CTO、技术总监、开发工程师可以使用打印机,假设某天不允许开发工程师使用打印机,此时需要从应用中删除相应代码;再如在应用中CTO、技术总监可以查看用户、查看权限;突然有一天不允许技术总监查看用户、查看权限了,需要在相关代码中把技术总监角色从判断逻辑中删除掉;即粒度是以角色为单位进行访问控制的,粒度较粗;如果进行修改可能造成多处代码修改。
在程序中通过权限控制谁能访问某个资源,角色聚合一组权限集合;这样假设哪个角色不能访问某个资源,只需要从角色代表的权限集合中移除即可;无须修改多处代码;即粒度是以资源/实例为单位的;粒度较细。、
Shiro支持三种方式的授权:
1.编程式:通过写if/else授权代码块完成:
Java代码
Subject subject = SecurityUtils.getSubject(); if(subject.hasRole(“admin”)) { //有权限 } else { //无权限 }
注解式:通过在执行的Java方法上放置相应的注解完成:
Java代码 收藏代码 @RequiresRoles("admin") public void hello() { //有权限 }
没有权限将抛出相应的异常;
JSP/GSP标签:在JSP/GSP页面通过相应的标签完成:
Java代码
<shiro:hasRole name="admin"> <!— 有权限 —> </shiro:hasRole>
这是我从公司一个勘察项目中截下的一段代码可以看到-->@RequiresRoles。。。。
它的意思就是后面的角色里只要用户有其中一个角色就可以使用这个方法
我们可以发现它先拿到一个userid,然后通过userid为key在redis中寻找value,然后将权限信息放入info返回,对此大家一定很好奇他在redis中拿了什么
我们查看redis发现它拿了一个数字
以上,就是今天的全部内容。
增鑫
芦苇科技Java开发工程师
芦苇科技-广州专业软件外包服务公司
提供微信小程序、APP应用研发、UI设计等专业服务,专注于互联网产品咨询、品牌设计、技术研发等领域、
访问 www.talkmoney.cn 了解更多
万能说明书 | 早起日记Lite | 凹凸壁纸 | 言财