shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证、用户受权。css
spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖过于紧密,没有shiro使用简单。
shiro不依赖于spring,shiro不只能够实现 web应用的权限管理,还能够实现c/s系统,分布式系统权限管理,shiro属于轻量框架,愈来愈多企业项目开始使用shiro。java
Shiro架构:web
cryptography:密码管理,提供了一套加密/解密的组件,方便开发。好比提供经常使用的散列、加/解密等功能。算法
咱们在使用URL拦截的时候,要将全部的URL都配置起来,繁琐、不易维护spring
而咱们的Shiro实现系统的权限管理,有效提升开发效率,从而下降开发成本。数据库
咱们使用的是Maven的坐标就好了apache
<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相关的jar包所有导入进去缓存
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.3</version>
</dependency>
// 用户登录和退出
@Test
public void testLoginAndLogout() {
// 建立securityManager工厂,经过ini配置文件建立securityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"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",
"111111");
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);
}
ModularRealmAuthenticator做用进行认证,须要调用realm查询用户信息(在数据库中存在用户信息)
ModularRealmAuthenticator进行密码对比(认证过程)。
realm:须要根据token中的身份信息去查询数据库(入门程序使用ini配置文件),若是查到用户返回认证信息,若是查询不到返回null。安全
从第一个认证程序咱们能够看见,咱们所说的流程,是认证器去找realm去查询咱们相对应的数据。而默认的realm是直接去与配置文件来比对的,通常地,咱们在开发中都是让realm去数据库中比对。
所以,咱们须要自定义realmmarkdown
public class CustomRealm extends AuthorizingRealm {
// 设置realm的名称
@Override
public void setName(String name) {
super.setName("customRealm");
}
// 用于认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// token是用户输入的
// 第一步从token中取出身份信息
String userCode = (String) token.getPrincipal();
// 第二步:根据用户输入的userCode从数据库查询
// ....
// 若是查询不到返回null
//数据库中用户帐号是zhangsansan
/*if(!userCode.equals("zhangsansan")){// return null; }*/
// 模拟从数据库查询到密码
String password = "111112";
// 若是查询到返回认证信息AuthenticationInfo
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
userCode, password, this.getName());
return simpleAuthenticationInfo;
}
// 用于受权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
}
}
须要在shiro-realm.ini配置realm注入到securityManager中。
同上边的入门程序,须要更改ini配置文件路径:
同上边的入门程序,须要更改ini配置文件路径:
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro-realm.ini");
咱们若是知道md5,咱们就会知道md5是不可逆的,可是若是设置了一些安全性比较低的密码:111111…即时是不可逆的,但仍是能够经过暴力算法来获得md5对应的明文…
建议对md5进行散列时加salt(盐),进行加密至关 于对原始密码+盐进行散列。\
正常使用时散列方法:
测试:
public class MD5Test {
public static void main(String[] args) {
//原始 密码
String source = "111111";
//盐
String salt = "qwerty";
//散列次数
int hashIterations = 2;
//上边散列1次:f3694f162729b7d0254c6e40260bf15c
//上边散列2次:36f2dfa24d0a9fa97276abbe13e596fc
//构造方法中:
//第一个参数:明文,原始密码
//第二个参数:盐,经过使用随机数
//第三个参数:散列的次数,好比散列两次,至关 于md5(md5(''))
Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations);
String password_md5 = md5Hash.toString();
System.out.println(password_md5);
//第一个参数:散列算法
SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations);
System.out.println(simpleHash.toString());
}
}
自定义realm
public class CustomRealmMd5 extends AuthorizingRealm {
// 设置realm的名称
@Override
public void setName(String name) {
super.setName("customRealmMd5");
}
// 用于认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// token是用户输入的
// 第一步从token中取出身份信息
String userCode = (String) token.getPrincipal();
// 第二步:根据用户输入的userCode从数据库查询
// ....
// 若是查询不到返回null
// 数据库中用户帐号是zhangsansan
/* * if(!userCode.equals("zhangsansan")){// return null; } */
// 模拟从数据库查询到密码,散列值
String password = "f3694f162729b7d0254c6e40260bf15c";
// 从数据库获取salt
String salt = "qwerty";
//上边散列值和盐对应的明文:111111
// 若是查询到返回认证信息AuthenticationInfo
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
userCode, password, ByteSource.Util.bytes(salt), this.getName());
return simpleAuthenticationInfo;
}
// 用于受权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
}
}
配置文件:
测试:
// 自定义realm实现散列值匹配
@Test
public void testCustomRealmMd5() {
// 建立securityManager工厂,经过ini配置文件建立securityManager工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:shiro-realm-md5.ini");
// 建立SecurityManager
SecurityManager securityManager = factory.getInstance();
// 将securityManager设置当前的运行环境中
SecurityUtils.setSecurityManager(securityManager);
// 从SecurityUtils里边建立一个subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备token(令牌)
// 这里的帐号和密码 未来是由用户输入进去
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
"222222");
try {
// 执行认证提交
subject.login(token);
} catch (AuthenticationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 是否定证经过
boolean isAuthenticated = subject.isAuthenticated();
System.out.println("是否定证经过:" + isAuthenticated);
}