shiro--认证部分
1.1
什么是
shiro
shiro
是
apache
的一个开源框架,是一个权限管理的框架,实现 用户认证、用户授权。
spring
中有
spring security (
原名
Acegi)
,是一个权限框架,它和
spring
依赖过于紧密,没有
shiro
使用简单。
shiro
不依赖于
spring
,
shiro
不仅可以实现
web
应用的权限管理,还可以实现
c/s
系统,分布式系统权限管理,
shiro
属于轻量框架,越来越多企业项目开始使用
shiro
。
使用
shiro
实现系统 的权限管理,有效提高开发效率,从而降低开发成本。
1.2
shiro
架构
subject
:主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。
securityManager
:安全管理器,主体进行认证和授权都 是通过
securityManager
进行。
authenticator
:认证器,主体进行认证最终通过
authenticator
进行的。
authorizer
:授权器,主体进行授权最终通过
authorizer
进行的。
sessionManager
:
web
应用中一般是用
web
容器对
session
进行管理,
shiro
也提供一套
session
管理的方式。
SessionDao
: 通过
SessionDao
管理
session
数据,针对个性化的
session
数据存储需要使用
sessionDao
。
cache Manager
:缓存管理器,主要对
session
和授权数据进行缓存,比如将授权数据通过
cacheManager
进行缓存管理,和
ehcache
整合对缓存数据进行管理。
realm
:域,领域,相当于数据源,通过
realm
存取认证、授权相关数据。
注意:在
realm
中存储授权和认证的逻辑。
cryptography
:
密码管理,提供了一套加密
/
解密的组件,方便开发。比如提供常用的散列、加
/
解密等功能。
比如
md5散列算法。
1.3
jar
包
与其它
java
开源框架类似,将
shiro
的
jar
包加入项目就可以使用
shiro
提供的功能了。
shiro-core
是核心包必须选用,还提供了与
web
整合的
shiro-web
、
与
spring
整合的
shiro-spring
、与任务调度
quartz
整合的
shiro-quartz
等,下边是
shiro
各
jar
包的
maven
坐标。
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-quartz</artifactId> <version>1.2.3</version> </dependency>
也可以通过引入shiro-all包括shiro所有的包:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.3</version>
</dependency>
参考lib目录 :
1
shiro
认证
1.1
shiro
认证流程
1.2
shiro
入门程序工程 环境
jar
包:
shiro-core.jar
工程结构:
1.3
shiro
认证入门程序
1.3.1
shiro-first.ini
通过此配置文件创建
securityManager
工厂。
需要修改
eclipse
的
ini
的编辑器
:
配置数据:
1.1.1
入门程序代码
//用户登陆和退出 @Testpublic voidtestLoginAndLogout() {//创建securityManager工厂,通过ini配置文件创建securityManager工厂 Factory<SecurityManager> factory = newIniSecurityManagerFactory("classpath:shiro-first.ini");//创建SecurityManager SecurityManager securityManager =factory.getInstance();//将securityManager设置当前的运行环境中 SecurityUtils.setSecurityManager(securityManager);//从SecurityUtils里边创建一个subject Subject subject =SecurityUtils.getSubject();//在认证提交前准备token(令牌) UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "666666666666");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);
}
1.1.1
执行流程
1
、通过
ini
配置文件创建
securityManager
2
、调用
subject.login
方法主体提交认证,提交的
token
3
、
securityManager进行认证,securityManager最终由ModularRealmAuthenticator进行认证。
4
、
ModularRealmAuthenticator调用IniRealm(
给
realm
传入
token)
去
ini
配置文件中查询用户信息
5
、
IniRealm
根据输入的
token
(
UsernamePasswordToken
)从
shiro-first.ini
查询用户信息,根据账号查询用户信息(账号和密码)
如果查询到用户信息,就给ModularRealmAuthenticator返回用户信息(账号和密码)
如果查询不到,就给ModularRealmAuthenticator
返回
null
6
、
ModularRealmAuthenticator接收IniRealm返回Authentication
认证信息
如果返回的认证信息是
null
,
ModularRealmAuthenticator抛出异常(
org.apache.shiro.authc.UnknownAccountException
)
如果返回的认证信息不是
null
(说明
inirealm
找到了用户),对
IniRealm
返回用户密码
(在
ini
文件中存在)和
token
中的密码 进行对比,如果不一致抛出异常(
org.apache.shiro.authc.IncorrectCredentialsException
)
个人解释一下上面说的:
securityManager最终由ModularRealmAuthenticator进行认证 《== 为什么是它认证
Ctrl+ T
查看
Authenticator
接口的超类型 层次结构。如下:
上图中会跑到
AuthenticatingSecurityManager
认证实现类,类里面有个属性
是由
ModularRealmAuthenticator创建的,
用接口authenticator
来引用
1.1.2
小结:
ModularRealmAuthenticator
作用进行认证,需要调用
realm
查询用户信息(在数据库中存在用户信息)
ModularRealmAuthenticator进
行密码对比
(认证过程)。
realm
:需要根据
token
中的身份信息去查询数据库(入门程序使用
ini
配置文件),如果查到用户返回认证信息,如果查询不到返回
null
。
1.1
自定义
realm
将来实际开发需要
realm
从数据库中查询用户信息。
1.1.1
realm
接口
1.1.1
自定义
realm
packagecn.itcast.shiro.realm;importjava.util.ArrayList;importjava.util.List;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.AuthenticationInfo;importorg.apache.shiro.authc.AuthenticationToken;importorg.apache.shiro.authc.SimpleAuthenticationInfo;importorg.apache.shiro.authz.AuthorizationInfo;importorg.apache.shiro.authz.SimpleAuthorizationInfo;importorg.apache.shiro.realm.AuthorizingRealm;importorg.apache.shiro.subject.PrincipalCollection;/***
* <p>
* Title: CustomRealm
* </p>
* <p>
* Description:自定义realm
* </p>
* <p>
* Company: www.itcast.com
* </p>
*
*@author传智.燕青
* @date 2015-3-23下午4:54:47
*@version1.0*/ public class CustomRealm extendsAuthorizingRealm {//设置realm的名称 @Overridepublic voidsetName(String name) {super.setName("customRealm");
}//用于认证 @OverrideprotectedAuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token)throwsAuthenticationException {//token是用户输入的//第一步从token中取出身份信息 String userCode =(String) token.getPrincipal();//第二步:根据用户输入的userCode从数据库查询//....//如果查询不到返回null//数据库中用户账号是zhangsansan /*if(!userCode.equals("zhangsansan")){//
return null;
}*/ //模拟从数据库查询到密码 String password = "666666666666";//如果查询到返回认证信息AuthenticationInfo SimpleAuthenticationInfo simpleAuthenticationInfo= newSimpleAuthenticationInfo(
userCode, password,this.getName());returnsimpleAuthenticationInfo;
}//用于授权 @OverrideprotectedAuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {//从 principals获取主身份信息//将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型), String userCode =(String) principals.getPrimaryPrincipal();//根据身份信息获取权限信息//连接数据库...//模拟从数据库获取到数据 List<String> permissions = new ArrayList<String>();
permissions.add("user:create");//用户的创建 permissions.add("items:add");//商品添加权限//....//查到权限数据,返回授权信息(要包括 上边的permissions) SimpleAuthorizationInfo simpleAuthorizationInfo = newSimpleAuthorizationInfo();//将上边查询到授权信息填充到simpleAuthorizationInfo对象中 simpleAuthorizationInfo.addStringPermissions(permissions);returnsimpleAuthorizationInfo;
}
}
1.1.1
配置
realm
需要在
shiro-realm.ini
配置
realm
注入到
securityManager
中。
1.1.2
测试
同上边的入门程序,需要更改
ini
配置文件路径:
Factory<SecurityManager> factory =
new
IniSecurityManagerFactory("classpath:shiro-realm.ini");
1.1
散列算法
通常需要对密码
进行散列,常用的有
md5
、
sha
,
对
md5
密码,如果知道散列后的值可以通过穷举算法,得到
md5
密码对应的明文。
建议对
md5
进行散列时加
salt
(盐),进行加密相当 于对原始密码
+
盐进行散列。
正常使用时散列方法:
在程序中对原始密码
+
盐进行散列,将散列值存储到数据库中,并且还要将盐也要存储在数据库中。
如果进行密码对比时,使用相同
方法,将原始密码
+
盐进行散列,进行比对。
1.1.1
md5
散列测试程序:
1.1.1
自定义
realm
支持散列算法
需求:实际开发时
realm
要进行
md5
值(明文散列后的值)的对比。
1.1.1.1
新建
realm(CustomRealmMd5)
在
realm
中配置凭证匹配器