当前位置首页 > Apache知识

">apache-shiro入门<一>

阅读次数:321 次  来源:admin  发布时间:

Apache Shiro是一个强大而灵活的开源安全框架(本来想传到网盘供大家下载,但是鉴于国内网盘动不动就要关闭清楚用户数据;所以我提供了另一个shiro的中文文档下载链接:http://download.csdn.net/detail/privacy_googol/9668807),它干净利落地处理身份认证,授权,企业会话管理和加密。在给大家介绍Shiro前,先给小白补充一点权限基础的知识。

安全实体:就是被权限系统保护的对象,比如工资数据。  

权限:就是需要被校验的行为,比如查看、修改等。

分配权限:把对某些安全实体的某些权限分配给某些人员。是向数据库里面添加数据、或是维护数据的过程

权限验证(权限匹配):判断某个人员或程序对某个安全实体是否拥有某个或某些权限。从数据库中获取相应数据进行匹配的过程。

权限的继承性:如果多个安全实体存在包含关系,而某个安全实体没有权限限制,则它会继承包含它的安全实体的相应权限。

权限的最近匹配原则:如果多个安全实体存在包含关系,而某个安全实体没有权限限制,那么它会向上寻找并匹配相应权限限制,直到找到一个离这个安全实体最近的拥有相应权限限制的安全实体为止。如果把整个层次结构都

寻找完了都没有匹配到相应权限限制的话,那就说明所有人对这个安全实体都拥有这个相应的权限限制。

Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和会话管理等功能 。

Shiro 能做什么 ???

认证:验证用户的身份

授权:对用户执行访问控制:判断用户是否被允许做某事

管理:在任何环境下使用 Session API,即使没有 Web 或EJB 容器。

加密:以更简洁易用的方式使用加密功能,保护或隐藏数据防止被偷窥

Realms:聚集一个或多个用户安全数据的数据源

单点登录(SSO)功能:为没有关联到登录的用户启用 "Remember Me“ 服务

Shiro 的主要功能

apache-shiro入门<一>" title="">apache-shiro入门<一>">

Shiro 的四大核心部分

Authentication(身份验证):简称为“登录”,即证明用户是谁。

Authorization(授权):访问控制的过程,即决定是否有权限去访问受保护的资源。

Session Management(会话管理):管理用户特定的会话,即使在非 Web 或 EJB 应用程序。

Cryptography(加密):通过使用加密算法保持数据安全

hiro 还提供以下扩展:

Web Support:主要针对web应用提供一些常用功能。

Caching:缓存可以使应用程序运行更有效率。

Concurrency:多线程相关功能。

Testing:帮助我们进行测试相关功能

"Run As":一个允许用户假设为另一个用户身份(如果允许)的功能,有时候在管理脚本很有用。

"Remember Me" :记住用户身份,提供类似购物车功能。

Shiro 架构 3 个核心组件

apache-shiro入门<一>" title="">apache-shiro入门<一>">

Subject :正与系统进行交互的人,或某一个第三方服务。所有 Subject 实例都被绑定到(且这是必须的)一个SecurityManager 上。

SecurityManager:Shiro 架构的心脏,用来协调内部各安全组件,管理内部组件实例,并通过它来提供安全管理的各种服务。当 Shiro 与一个 Subject 进行交互时,实质上是幕后的 SecurityManager 处理所有繁重的

Subject 安全操作。

Realms :本质上是一个特定安全的 DAO。当配置 Shiro 时,必须指定至少一个 Realm 用来进行身份验证或授权。Shiro 提供了多种可用的 Realms 来获取安全相关的数据。如关系数据库(JDBC),INI 及属性文件等。可以

定义自己 Realm 实现来代表自定义的数据源。

Shiro 架构

apache-shiro入门<一>" title="">apache-shiro入门<一>">

Authenticator :执行对用户的身份验证(登录)的组件。Authenticator 从一个或多个 Realm 中获得数据以验证用户的身份。 若存在多个realm,则接口 AuthenticationStrategy 会确定什么样算是验证成功(例如,如果一个 Realm 成功,而其他的均失败,是否登录成功)。

Authorizer :验证用户能否访问应用中的受保护的资源。

SessionManager :可在任何应用或架构层一致地使用 Session API

SessionDAO:SessionManager 执行 Session 持久化(CRUD)操作。

CacheManager :对 Shiro 组件提供缓存支持。

Cryptography:Shiro 的 API 大幅度简化 Java API 中繁琐的密码加密

Realms:Shiro 通过 Realms 来获取相应的安全数据

Shiro 配置基础:user

Shiro 被设计成能够在任何环境下工作,从简单的命令行应用程序到企业群集应用。由于环境的多样性,使得 Shiro 可以使用多种配置机制。

ini 配置:ini 实际上是一个文本配置,包含了由唯一命名的项来组织的键/值对。

[users] 部分允许定义一组静态的用户帐户

每行的格式:username = password, roleName1, roleName2, …

Shiro 配置基础:role

[roles] 部分允许把定义在 [users] 部分中的角色与权限关联起来

每行的格式:rolename = permissionDefinition1, permissionDefinition2, …

ermissionDefinition 是一个任意的字符串,但大多数人将会使用符合 org.apache.shiro.authz.permission.WildcardPermission 格式的字符串。

注意:

如果一个独立的 permissionDefinition 需要被内部逗号分隔(例如,printer:5thFloor:print,info),则需要用户双引号环绕该定义,以避免错误解析。  

如果角色不想关联权限,则不需要在 [roles] 部分把它们列出来。只需定义在 [user] 部分中定义角色名就足以创建尚不存在的角色。

仅定义非空的 [users] 或 [roles] 部分就将自动地触发org.apache.shiro.realm.text.IniRealm 实例的创建

Shiro 的 Permissio

基础语法之简单的字符串:即用简单的字符串来表示一个权限,如:user (相当于:user:*)

基础语法之多层次管理:

例如:user:query、user:edit

多个值:每个部件能够保护多个值。因此,除了授予用户 user:query 和 user:edit 权限外,也可以简单地授予他们一个:user:query, edit

还可以用 * 号代替所有的值,如:user:* , 也可以写:*:query,表示某个用户在所有的领域都有 query 的权限

基础语法之实例级访问控制

这种情况通常会使用三个部件:域、操作、被付诸实施的实例。如:user:edit:manager

也可以使用通配符来定义,如:user:edit:*、user:*:*、user:*:manager

部分省略通配符:缺少的部件意味着用户可以访问所有与之匹配的值,比如:user:edit 等价于 user:edit :*、user 等价于 user:*:*

注意:通配符只能从字符串的结尾处省略部件,也就是说 user:edit 并不等价于 user:*:edit

身份认证:Authenticatio

Authentication :身份验证——通过提交用户的身份和凭证给 Shiro,以判断它们是否和应用程序预期的相匹配。

基本概念

Principals(身份):Subject 的 identifying attributes(标识属性)。比如我们登录提交的用户名。

Credentials(凭证):用来作为一种起支持作用的证据,此证据包含身份证明。比如我们登录提供的密码

认证的基本步骤

收集Subjects 提交的Principals(身份)和Credentials(凭证);

提交Principals(身份)和Credentials(凭证)进行身份验证;

如果提交成功,则允许访问,否则重新进行身份验证或者阻止访问。

AuthenticationToken:Shiro 中代表提交的 Principals(身份) 和 Credentials (凭证) 的身份验证系统的最基本接口。

UsernamePasswordToken :AuthenticationToken 的接口的实现类,支持最常见的用户名/密码的身份验证

提交用户名/密码进行认证

Subject currentUser = SecurityUtils.getSubject()

currentUser.login(token)

处理认证成功和失败

认证成功:没有返回,也没有异常,通过。

认证失败,拋出异常,可以在程序中捕获并处理

认证顺序

apache-shiro入门<一>" title="">apache-shiro入门<一>">

认证过程

apache-shiro入门<一>" title="">apache-shiro入门<一>">

Step 1:应用程序代码调用 Subject.login 方法,传递创建好的包含终端用户的 Principals(身份)和 Credentials(凭证)的 AuthenticationToken 实例

Step 2:Subject 实例,通常为 DelegatingSubject(或子类)委托应用程序的 SecurityManager 通过调用 securityManager.login(token) 开始真正的验证。

Step 3:SubjectManager 接收 token,调用内部的 Authenticator 实例调用 authenticator.authenticate(token)。 Authenticator 通常是一个 ModularRealmAuthenticator 实例,支持在身份验证中协调一个或多个Realm 实例。

Step 4:如果应用程序中配置了一个以上的 Realm,ModularRealmAuthenticator 实例将利用配置好的AuthenticationStrategy 来启动 Multi-Realm 认证尝试。在Realms 被身份验证调用之前,期间和以后,

AuthenticationStrategy 被调用使其能够对每个Realm 的结果作出反应。

Step 5:每个配置的 Realm 用来帮助看它是否支持提交的AuthenticationToken。如果支持,那么支持 Realm 的 getAuthenticationInfo 方法将会伴随着提交的 token 被调用。getAuthenticationInfo 方法有效地代表一

个特定 Realm 的单一的身份验证尝试。

注销

logout(注销):currentUser.logout()

调用 logout() 方法时,现有 Session 将失效,而且身份将失去关联(在Web 应用程序中,RememberMe cookie 将被删除)。

在 Subject 注销后,该 Subject 的实例被再次认为是匿名的。

注意:WEB 应用程序记住身份往往依靠 Cookie,然而Cookie 只能在 Response 被返回后被删除,所以建议在调用subject.logout() 后立即向终端重定向一个新的视图或页面。这样即能保证与安全相关的 Cookie 都能像预期的

一样被删除。

授权: Authorizatio

授权:又称访问控制—控制谁有权限在应用程序中做什么。

授权检查的例子:用户是否能访问某个网页,编辑数据,或打使用这台打印机

授权的三要素:权限、角色和用户 。

需要在应用程序中对用户和权限建立关联:通常的做法是将权限分配给角色,然后将角色分配给一个或多个用户。

权限:Shiro 安全机制最核心的元素。它在应用程序中明确声明了被允许的行为。一个格式良好的权限声明可以清晰表达出用户对该资源拥有的权限。在 Shiro 中主要通过通配符表达式来完成权限的描述。

角色:Role

角色:一个命名的实体, 通常代表一组行为或职责。 这些行为演化为在一个应用中能或者不能做的事情。角色通常分配给用户帐户

一个角色拥有一个权限的集合。授权验证时,需要判断当前角色是否拥有指定的权限。这种角色权限可以对该角色进行详细的权限描述。 Shiro官方推荐使用这种方式。

Shiro的三种授权方式

编写代码:在 Java 代码中用像 if 和 else 块的结构执行授权检查。

JDK 的注解:可以添加授权注解给 Java 方法

JSP 标签库:可以控制基于角色和权限的JSP 页面输出。

编程授权

通过使用 subject 的方法来实现角色的判断,常用的 API:

hasRole(String roleName)

hasRoles(List<String> roleNames)

hasAllRoles(Collection<String> roleNames)

断言支持:

Shiro 还支持以断言的方式进行授权验证。断言成功,不返回任何值,程序继续执行;断言失败时,将抛出异常信息。常用方法:

checkRole(String roleName) 、

checkRoles(Collection<String>roleNames)、

checkRoles(String… roleNames)

基于权限对象的实现

isPermitted(Permission p)、isPermitted(List<Permission> perms)、isPermittedAll(Collection<Permission> perms)

基于字符串的实现

if (currentUser.isPermitted("printer:print:laserjet4400n"))

isPermitted(String perm)、isPermitted(String... perms)、isPermittedAll(String... perms)

权限的实现也都可以采用断言的方式,相关方法:

checkPermission(Permission p)、checkPermission(String perm)、checkPermissions(Collection<Permission> perms)、checkPermissions(String... perms)

授权的顺序

apache-shiro入门<一>" title="">apache-shiro入门<一>">

apache-shiro入门<一>" title="">apache-shiro入门<一>">

Step 1:应用程序或框架代码调用任何 Subject 的hasRole*, checkRole*, isPermitted*,或者checkPermission*方法的变体,传递任何所需的权限

Step 2:Subject 的实例—通常是 DelegatingSubject(或子类),调用securityManager 的对应的方法。

Step 3:SecurityManager 调用 org.apache.shiro.authz.Authorizer 接口的对应方法。默认情况下,authorizer 实例是一个 ModularRealmAuthorizer 实例,它支持协调任何授权操作过程中的一个或多个Realm 实例。

Step 4:每个配置好的 Realm 被检查是否实现了相同的 Authorizer 接口。如果是,Realm 各自的 hasRole*, checkRole*,isPermitted*,或 checkPermission* 方法将被调用。

Realm

Realm:访问应用程序安全数据(如用户、角色及权限)的组件。

Realm 通常和数据源是一对一的对应关系,如关系数据库、文件系统或其他类似资源。Realm 实质上就是一个访问安全数据的 DAO。

数据源通常存储身份验证数据(如密码的凭证)以及授权数据(如角色或权限),所以每个Realm 都能够执行身份验证和授权操作。

Realms的认证实现

Shiro 的认证过程由 Realm 执行,SecurityManager 会调用 org.apache.shiro.realm.Realm 的 getAuthenticationInfo(AuthenticationToken token) 方法。

实际开发中,通常会提供 org.apache.shiro.realm.AuthenticatingRealm 的实现类,并在该实现类中提供 doGetAuthenticationInfo(AuthenticationToken token)方法的具体实现

1、检查提交的进行认证的令牌信息

2、根据令牌信息从数据源(通常为数据库)中获取用户信息

3、对用户信息进行匹配验证。

4、验证通过将返回一个封装了用户信息的 AuthenticationInfo 实例。

5、验证失败则抛出 AuthenticationException 异常信息。

Spring 集成 Shiro (本次[第一篇以理论为主]以非Maven的Web的项目示例,在我之后[以实战为主]的“apache-shiro入门”系列我会以Maven项目示例)

1. 加入相关 jar 包

2. 配置 web.xml 文件   

配置启动 Spring IOC 容器的 Filter 

配置 WEB 应用中的 Shiro Filter

apache-shiro入门<一>" title="">apache-shiro入门<一>">

3. 在 Spring 的配置文件中配置 Shiro

配置自定义 Realm:实现自定义认证和授权

配置 Shiro 实体类使用的缓存策略

配置 SecurityManager

配置保证 Shiro 内部 Bean 声明周期都得到执行的 Lifecycle Bean 后置处理器

配置AOP 式方法级权限检查

配置 Shiro Filter   

filterChainDefinitions 属性:设置 Shiro Filter 拦截的 URL 及访问该 URL 所需要的权限信息。

格式:URL_Ant_Path_Expression = Path_Specific_Filter_Chain。

等号左边是一个与 Web 应用程序上下文根目录相关的Ant 风格的路径表达式。

等号右边是逗号隔开的过滤器列表,用来执行匹配该路径的请求

Ant 风格资源地址支持 3 种匹配符:

?:匹配文件名中的一个字符

*:匹配文件名中的任意字符

**:** 匹配多层路径

路径表达式    

URL 权限采取第一次匹配优先的方式

比如:

/account/** = ssl, authc

/account/signup = ano

如果传入的请求访问是 /account/signup/index.html,则会匹配 ssl, authc 权限,而 annon 将永不会被匹配!因为/account/** 匹配 短路了其余的权限定义

权限信息    

权限是用逗号隔开的过滤器列表,用来执行对该路径请求的匹配。

必须符合以下格式:filter1[optional_config1], filter2[optional_config2],...

filterN:一个 shiro 中的过滤器的别名

[optional_configN] :可选的权限字符串。若该过滤器对该 URL 路径不需要特定的配置,可以忽略括号,于是 filteN[] 就变成了filterN.

hiro中默认的过滤器

apache-shiro入门<一>" title="">apache-shiro入门<一>">

authc 和 user 

user 和 authc :当应用开启了rememberMe 时,用户下次访问时是一个 user,但不是 authc,因为authc是需要重新认证的

user 表示用户不一定已通过认证,只要被 Shiro 记住过登录状态的用户就可以正常发起请求,比如rememberMe

简言之:以前的一个用户登录时开启了rememberMe,然后他关闭浏览器,下次再访问时他就是一个user,而不是authc

Remembered 和 Authenticated 

Remembered(记住我):

一个 记住我 的 Subject 不是匿名的,是有一个已知的身份ID(也就是subject.getPrincipals()是非空的)。即:这个被记住的身份 ID 是在之前的session 中被认证的。

如果 subject.isRemembered() 返回 true,则 Subject 被认为是被记住的。

Authenticated(已认证):

一个已认证的 Subject 是指在当前 Session 中被成功地验证过:login方法被调用并且没有抛出异常

如果 subject.isAuthenticated()返回 true 则认为 Subject 已通过验证。

注意:Remembered 和Authenticated 是互斥的——若其中一个为真则另一个为假,反之亦然

基于注解的授权

Shiro提供的注解

@RequiresAuthentication :要求当前 Subject 已经在当前的session 中被验证通过才能被注解的类/实例/方法访问或调用。

@RequiresGuest :要求当前的 Subject 是一个 “guest”,也就是他们必须是在之前的 session 中没有被验证或记住才能被注解的类/实例/方法访问或调用。

@RequiresPermissions:要求当前的 Subject 被允许一个或多个权限,以便执行注解的方法,比如:@RequiresPermissions("account:create")

@RequiresRoles:要求当前的 Subject 拥有所有指定的角色。如果他们没有,则该方法将不会被执行,而且 AuthorizationException 异常将会被抛出。比如:@RequiresRoles("administrator")

@RequiresUser:需要当前的Subject 是一个应用程序用户才能被注解的类/实例/方法访问或调用。要么是通过验证被确认,或者在之前session 中的 'RememberMe‘ 服务被记住。

apache-shiro入门<一>" title="">apache-shiro入门<一>">

基于标签库的授权:guest

guest 标签将显示它包含的内容,仅当当前的Subject 被认为是 guest 时。

guest 是指没有身份 ID 的任何 Subject:没有登录也没有在上一次的访问中被记住(RememberMe 服务)

guest 标签与user 标签逻辑相反。

user 标签将显示它包含的内容,仅当当前的 Subject 被认为是 user 时。

User 在上下文中被定义为一个已知身份 ID 的 Subject,或是成功通过身份验证及通过 RememberMe 服务的。

该标签在语义上与authenticated 标签是不同的,authenticated 标签更为严格。

usre 标签与guest 标签逻辑相反。

authenticated:当当前用户在当前会话中成功地通过了身份验证 authenticated 标签才会显示包含的内容。比 user 标签更为严格。在逻辑上与 notAuthenticated 标签相反。

otAuthenticated:当前 Subject 还没有在其当前会话中成功地通过验证,将会显示它所包含的内容

rincipal 标签将会输出Subject 的主体(标识属性)或主要的属性

hasRole 当当前Subject 被分配了具体的角色时显示它所包含的内容。hasRole 标签与lacksRole 标签逻辑相反。

lacksRole 标签:当当前Subject 未被分配具体的角色,显示它所包含的内容

hasAnyRole 标签:当前的 Subject 被分配了任意一个来自于逗号分隔的角色名列表中的具体角色,将会显示它所包含的内容。例如:

lt;shiro:hasAnyRoles name="developer, project manager, administrator">

You are either a developer, project manager, or administrater.

lt;/shiro:hasAnyRoles>

hasPermission 标签:当前 Subject 拥有特定的权限时,会显示它所包含的内容。hasPermission 标签与 lacksPermission 标签逻辑相反。例如:

lt;shiro:hasPermission name="user:create">

lt;a href="createUser.jsp">Create a new User</a>

lt;/shiro:hasPermission>

lacksPermission 标签:当前Subject 没有拥有(蕴含)特定的权限,将会显示它所包含的内容。也就是说,用户没有特定的能力。

密码加密

1. 在 Realm 的 init 方法中设置凭证匹配器

apache-shiro入门<一>" title="">apache-shiro入门<一>">

2. 认证时返回的 SimpleAuthenticationInfo 包含的密码若是需要是经过加密后的密码。若有盐值,需要包含 credentialsSalt 参数

apache-shiro入门<一>" title="">apache-shiro入门<一>">

3. 向数据库中保存密码时需要保存加密后的密码

apache-shiro入门<一>" title="">apache-shiro入门<一>">

转载请注明出处!

http://www.cnblogs.com/libingbin/

感谢您的阅读。如果文章对您有用,那么请轻轻点个赞,以资鼓励。

上一篇:nginx“403Forbidden”错误的原因及解决办法
下一篇:debian-11.0.0-amd64