文档章节

第四章:Shiro的身份认证(Authentication)——深入浅出学Shiro细粒度权限开发框架

MonroeCode
 MonroeCode
发布于 2017/03/19 16:25
字数 1807
阅读 7
收藏 0

Authentication概述

n概述

  Authentication 是指身份验证的过程——即证明一个用户实际上是不是他们所说的他们是谁。也就是说通过提交用户的身份和凭证给Shiro,以判断它们是否和应用程序预期的相匹配。

n基本概念

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

2:Credentials(凭证):通常是只被Subject 知道的秘密值,它用来作为一种起支持作用的证据,此证据事实上包含着所谓的身份证明。比如我们登录提供的密码

 

n认证的基本步骤

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

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

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

 

认证样例

n使用用户名/密码的样例

UsernamePasswordToken token = new UsernamePasswordToken(username, password);

token.setRememberMe(true);

  样例使用UsernamePasswordToken 来支持最常见的用户名/密码的身份验证方法。这是Shiro的org.apache.shiro.authc.AuthenticationToken 的接口,是Shiro 代表提交的Principals(身份)和Credentials(凭证)的身份验证系统所使用的基本接口的一个实现。

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

Subject currentUser = SecurityUtils.getSubject();

currentUser.login(token);

n处理认证成功和失败

  如果认证成功,会没有返回,也没有例外,通过。

  如果认证失败,会拋出例外,你可以在程序中捕获并处理,如下示例:

 

try {

  currentUser.login(token);

} catch ( UnknownAccountException uae ) { …

} catch ( IncorrectCredentialsException ice ) { …

} catch (LockedAccountException lae ) { …

} catch (ExcessiveAttemptsException eae ) { …

} … catch your own …

nlogout(注销)

  currentUser.logout();

  当你调用logout,任何现有的Session 都将会失效,而且任何身份都将会失去关联(例如,在Web 应用程序中,RememberMe cookie 也将被删除)。在Subject 注销后,该Subject的实例被再次认为是匿名的,当然,除了Web 应用程序。

  注意:由于在Web 应用程序记住身份往往是依靠Cookies,然而Cookies 只能在Response 被committed 之前被删除,所以强烈建议在调用subject.logout()后立即将终端用户重定向到一个新的视图或页面。

  这样能够保证任何与安全相关的Cookies 都能像预期的一样被删除。这是HTTP cookies 的功能限制,而不是Shiro的。

 

Remembered和Authenticated

nRemembered(记住我)

  一个记住我的Subject 不是匿名的,是有一个已知的身份ID(也就是subject.getPrincipals()是非空的)。但是这个被记住的身份ID 是在之前的session 中被认证的。如果subject.isRemembered()返回true,则Subject 被认为是被记住的。

 

nAuthenticated(已认证)

  一个已认证的Subject 是指在当前Session 中被成功地验证过了(也就是说,login方法被调用并且没有抛出异常)。如果subject.isAuthenticated()返回true 则认为Subject 已通过验证。

 

n注意他们是互斥的

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

 

认证顺序

 

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

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

nStep3:SubjectManager 接收token 以及简单地委托给内部的Authenticator 实例通过调用authenticator.authenticate(token)。这通常是一个ModularRealmAuthenticator 实例,支持在身份验证中协调一个或多个Realm 实例。

n

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

n

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

初识自定义 Realm

n这里先来个例子,认识一下:

public class MyRealm extends AuthorizingRealm{

  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

  String userName = (String) getAvailablePrincipal(principals);

  //通过用户名去获得用户的所有资源,并把资源存入info中

  SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

  Set<String> s = new HashSet<String>();

  s.add("p1");  s.add("p2"); info.setStringPermissions(s);

  Set<String> r = new HashSet<String>();

  r.add("r1"); r.add("r2"); info.setRoles(r);

  return info;}

  protected AuthenticationInfo doGetAuthenticationInfo(

  AuthenticationToken token) throws AuthenticationException {

  //token中储存着输入的用户名和密码

  UsernamePasswordToken upToken = (UsernamePasswordToken)token;

  String username = upToken.getUsername();

  String password = String.valueOf(upToken.getPassword());

  //通常是与数据库中用户名和密码进行比对,这里就省略了

  //比对成功则返回info,比对失败则抛出对应信息的异常AuthenticationException

  SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password .toCharArray(),getName());

  return info;  }}

 

 

配置多个Realm

n上面的例子可以作为第一个Realm

n再复制一份,定义为MyRealm2,在返回user前添加抛出一个例外,表示认真没有通过,如下:

if(username.equals("javass")){

  throw new AuthenticationException("MyRealm2 认证失败");

}

SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password .toCharArray(),getName());

n在配置文件里面添加Realm的定义

myRealm1=cn.javass.hello.MyRealm

myRealm2=cn.javass.hello.MyRealm2

 

由于有多个realm,一般就需要配置AuthenticationStrategy了,而AuthenticationStrategy是跟Authenticator(认证器)相关的。

 

 

n配置Authenticator和AuthenticationStrategy

authenticator = org.apache.shiro.authc.pam.ModularRealmAuthenticator

authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy

authenticator.authenticationStrategy = $authcStrategy

authenticator.realms=$myRealm2,$myRealm1

n当然,你可以扩展并实现自己的Authenticator,一般没有必要

n最后把Authenticator设置给securityManager

  securityManager.authenticator = $authenticator

n关于AuthenticationStrategy的配置,有三种:

AtLeastOneSuccessfulStrategy :如果一个(或更多)Realm 验证成功,则整体的尝试被认为是成功的。如果没有一个验证成功,则整体尝试失败。

FirstSuccessfulStrategy 只有第一个成功地验证的Realm 返回的信息将被使用。所有进一步的Realm 将被忽略。如果没有一个验证成功,则整体尝试失败

AllSucessfulStrategy 为了整体的尝试成功,所有配置的Realm 必须验证成功。如果没有一个验证成功,则整体尝试失败。

 

ModularRealmAuthenticator 默认的是AtLeastOneSuccessfulStrategy

 

 

n自定义自己的AuthenticationStrategy,通常是扩展自AbstractAuthenticationStrategy,示例如下:

public class MyAuthenticationStrategy extends AbstractAuthenticationStrategy{

  public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {

  if(realm.getName().equals("myRealm2")){

  if(singleRealmInfo==null || singleRealmInfo.getPrincipals()==null){

  throw new AuthenticationException("主战认证未通过");

  }

  }

return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);

  }

}

至于具体覆盖扩展什么方法,需要根据你具体的策略来定。

 

 

多个Realm的验证顺序

n概述

  非常重要的一点是:ModularRealmAuthenticator 将与Realm 实例以迭代的顺序进行交互。

  在SecurityManager 中已经配置好了ModularRealmAuthenticator 对Realm实例的访问。当执行一个认证尝试时,它将会遍历该集合,并对每一个支持提交AuthenticationToken 的Realm 调用Realm 的getAuthenticationInfo 方法

n隐式排列

  当你配置多个realm的时候,处理的顺序默认就是你配置的顺序。

  这种情况通常就是只定义了realm,而没有配置securityManager的realms

n显示排列

  也就是显示的配置securityManager.realms,那么执行的顺序就是你配置该值的realm的顺序。

  通常更推荐显示排列。

© 著作权归作者所有

MonroeCode

MonroeCode

粉丝 89
博文 135
码字总数 225843
作品 0
深圳
运营/编辑
私信 提问
第一章 Shiro简介——《跟我学Shiro》

1.1 简介 Apache Shiro是Java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不...

真爱2015
2015/12/15
87
0
第一章 Shiro简介——跟我学习springmvc shiro mybatis

1.1 简介 Apache Shiro是Java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不...

CPU滴
2017/06/14
0
0
Shiro之身份认证、与spring集成(入门级)

目录1.Shro的概念2.Shiro的简单身份认证实现3.Shiro与spring对身份认证的实现   前言:   Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在 JavaSE 环境,也可以用在 JavaEE 环境...

左羽
2018/05/03
0
0
跟我学Shiro

1.1 简介 Apache Shiro是Java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不...

kevin728971010
2016/10/25
122
0
Shiro学习之路 Hello Shiro(一)

由于最近自己的项目需要加入权限的功能所以使用Shiro整合Spring mvc来实现。 Shiro简介 Shiro是一个拥有许多综合性的程序安全框架。有非常方便的身份认证、授权、企业会话管理和加密。 Shir...

汪梓文
2016/11/16
33
0

没有更多内容

加载失败,请刷新页面

加载更多

一文读懂深度学习:从神经元到BERT

阿里妹导读:自然语言处理领域的殿堂标志 BERT 并非横空出世,背后有它的发展原理。今天,蚂蚁金服财富对话算法团队整理对比了深度学习模型在自然语言处理领域的发展历程。从简易的神经元到当...

阿里云官方博客
16分钟前
1
0
0.03-CentOS安装配置

1、安装 -1.1、虚拟器启动后出现如下图 ① Install CentOS 7 :安装CentOS7 ② Test this media & Install CentOS 7 :测试安装文件并安装CentOS 7 ③ Troubleshooting :修复故障 -1.2、选择...

静以修身2025
18分钟前
1
0
Weblogic 共享库部署

Weblogic 共享库部署 目录 1. 生成共享库 2 1.1. 准备阶段 2 1.2. 打包 3 1.3. 部署共享库 3 2. 生成应用程序 4 3. 部署注意事项 4 生成共享库 我们一般把一些公共配置文件,打成共享库,在部...

internetafei
19分钟前
2
0
boost log库链接问题

1. 使用动态库时,要定义 BOOST_LOG_DYN_LINK 或者 BOOST_ALL_DYN_LINK 否则会出现如下错误: CMakeFiles/IrcChatData.dir/src/main.cpp.o: In function `boost::log::v2s_mt_posix::source......

BeyondWXF
23分钟前
1
0
ETCD数据库备份与还原

1 备份etcd数据 etcdctl backup --data-dir /var/lib/etcd/default.etcd --backup-dir /root/etcdback 2 etcd备份脚本 #!/bin/bashdate_time=`date +%Y%m%d`etcdctl backup --data-dir /......

拜了个拜
33分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部