Shiro学习笔记——(4)身份认证
2018-04-01 00:19
405 查看
一、环境项目搭建
(1)Maven依赖
<dependencies> <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <!-- https://mvnrepository.com/artifact/log4j/log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.5</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
(2)配置log4j.properties日志文件
log4j.rootLogger=debug, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
(3)创建shiro.ini文件
即 用户身份/凭据通过Shiro.ini配置文件初始化SecurityManager环境。#对用户信息进行配置 [users] #用户名密码 zhang=123 lisi=123配置 eclipse支持ini文件编辑:
二、用户认证
(1)代码实现
com.shiro.authentication.AuthenticationTest.javapublic class AuthenticationTest {/**
* 登录和登出
*/
@Test
public void testLoginAndLogOut() {
// 构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro.ini");
// 通过工厂创建SecurityManager
SecurityManager securityManager = factory.getInstance();
// 将securityManager设置当前的运行环境中
SecurityUtils.setSecurityManager(securityManager);
// 从SecurityUtils里边创建一个subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
try {
// 执行认证提交
subject.login(token);
} catch (AuthenticationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 是否认证通过
boolean isAuthenticated = subject.isAuthenticated();
System.out.println("是否认证通过:" + isAuthenticated);
// 退出操作
subject.logout();
// 是否认证通过
isAuthenticated = subject.isAuthenticated();
System.out.println("是否认证通过:" + isAuthenticated);
}
}
(2)执行流程
前置代码流程首先通过new IniSecurityManagerFactory并指定一个ini配置文件来创建一个SecurityManager工厂;
接着获取SecurityManager并绑定到SecurityUtils,这是一个全局设置,设置一次即可;
通过SecurityUtils得到Subject,其会自动绑定到当前线程;如果在web环境在请求结束时需要解除绑定;然后获取身份验证的Token,如用户名/密码;
认证流程:
通过ini配置文件创建securityManager
创建token令牌,token中有用户提交的认证信息即账号和密码
调用subject.login方法主体提交认证,提交的token
securityManager进行认证,securityManager最终由ModularRealmAuthenticator进行认证。
Authenticator的实现ModularRealmAuthenticato调用IniRealm(给realm传入token) 去ini配置文件中查询用户信息
IniRealm根据输入的token(UsernamePasswordToken)从shiro.ini查询用户信息,根据账号查询用户信息(账号和密码)。查询到用户信息,给ModularRealmAuthenticator返回用户信息(账号和密码)。如果查询不到,就给ModularRealmAuthenticator返回null。
ModularRealmAuthenticator接收IniRealm返回Authentication认证信息。ModularRealmAuthenticator对IniRealm返回用户密码 (在ini文件中存在)和 token中的密码 进行对比。
如果身份验证失败捕获AuthenticationException或其子类,常见的如: DisabledAccountException(禁用的帐号)、LockedAccountException(锁定的帐号)、UnknownAccountException(错误的帐号)、ExcessiveAttemptsException(登录失败次数过多)、IncorrectCredentialsException (错误的凭证)、ExpiredCredentialsException(过期的凭证)等,具体请查看其继承关系;
三、自定义Realm
(1)Realm介绍
Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。如我们之前的ini配置方式将使用org.apache.shiro.realm.text.IniRealm。Realm相当于上述的配置文件:shiro.ini 存储用户名密码
(2)Realm接口架构
最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm。
(3)自定义Realm代码
public class MyRealm extends AuthorizingRealm { @Override public String getName() { return "myrealm1"; } /** * 用于认证 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 从token中 获取用户身份信息 String username = (String) token.getPrincipal(); // 拿username从数据库中查询 // .... // 如果查询不到则返回null if (!username.equals("zhang")) {// 这里模拟查询不到 return null; } // 获取从数据库查询出来的用户密码 String password = "123";// 这里使用静态数据模拟。。 // 返回认证信息由父类AuthenticatingRealm进行认证 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, this.getName()); return simpleAuthenticationInfo; } }在shiro中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份:principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals,但只有一个Primary principals,一般是用户名/密码/手机号。credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。最常见的principals和credentials组合就是用户名/密码了。接下来先进行一个基本的身份认证。
(4)配置Realm
ini配置文件指定自定义Realm实现(shiro-realm.ini) #声明一个realmmyRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1
#指定securityManager的realms实现
securityManager.realms=$myRealm1 通过$name来引入之前的realm定义,相当于spring中的注入
(5)测试
同上边的入门程序,需要更改ini配置文件路径:Factory<SecurityManager>factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");四、Realm支持MD5加密
通常需要对密码 进行散列,常用的有md5、sha,对md5密码,如果知道散列后的值可以通过穷举算法,得到md5密码对应的明文。
建议对md5进行散列时加salt(盐),进行加密相当 于对原始密码+盐进行散列。
正常使用时散列方法:
在程序中对原始密码+盐进行散列,将散列值存储到数据库中,并且还要将盐也要存储在数据库中。
如果进行密码对比时,使用相同 方法,将原始密码+盐进行散列,进行比对。
(1)MD5本地测试
public class MD5Test { public static void main(String[] args) { /** * Md5Hash */ // 要加密的字符串 String source = "123"; // 盐 String salt = "1"; // 加密次数 int hashIterations = 1024; Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations); System.out.println(md5Hash.toString()); /** * SimpleHash */ // 使用的算法名称 String algorithmName = "MD5"; SimpleHash simpleHash = new SimpleHash(algorithmName, source, salt, hashIterations); System.out.println(simpleHash.toString()); } }
6932058980060f2c9130b59fd53b063b 6932058980060f2c9130b59fd53b063b
(2)自定义realm支持散列算法
1、Realm代码
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { // 从token中 获取用户身份信息 String username = (String) token.getPrincipal(); // 拿username从数据库中查询 // 如果查询不到则返回null if (!username.equals("zhang")) {// 这里模拟查询不到 return return null; } // 获取从数据库查询出来的用户密码123 String password = "6932058980060f2c9130b59fd53b063b"; // 从数据库查询出来的盐 String salt = "1"; // 返回认证信息由父类AuthenticatingRealm进行认证 SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, ByteSource.Util.bytes(salt), this.getName()); return simpleAuthenticationInfo; }2、在realm中配置凭证匹配器
[main] #定义凭证匹配器 credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher #散列算法 credentialsMatcher.hashAlgorithmName=md5 #散列次数 credentialsMatcher.hashIterations=1024 #将凭证匹配器设置到realm customRealm=com.shiro.realm.MD5Realm customRealm.credentialsMatcher=$credentialsMatcher securityManager.realms=$customRealm
相关文章推荐
- Shiro 学习笔记(1)-Helloworld 和 身份认证
- Shiro学习随笔【二】身份认证
- shiro学习笔记——从源码角度分析shiro身份验证过程
- Shiro学习随笔【二】身份认证
- [shiro学习笔记]第二节 shiro与web融合实现一个简单的授权认证
- MVC4学习笔记之--身份认证过滤器
- Shiro学习随笔【二】身份认证
- 【安全牛学习笔记】思路、身份认证方法、密码破解方法、字典
- Apache shiro 笔记整理之身份认证
- 学习Shiro——采用jdbcRealm实现身份认证
- Shiro学习随笔【二】身份认证
- java安全框架-Shiro学习笔记(三)-权限认证
- HTTP学习笔记10 用户身份认证
- shiro入门实战笔记(3)--身份认证
- Shiro学习随笔【二】身份认证
- Shiro学习随笔【二】身份认证
- SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存
- Shiro 学习笔记(二)——shiro身份验证
- Shiro学习随笔【二】身份认证
- Shiro学习随笔【二】身份认证