什么是权限管理
shiro各功能解释
shiro.ini配置文件使用,此处简单作为读取的数据库中的用户信息,方便前期测试
shiro认证流程
1 shiro简单认证演示 此处为测试从shiro.ini配置中读取数据
public class TestAuthenticator {
public static void main(String[] args) throws NamingException {
//1.创建安全管理器对象
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//2.给安全管理器设置realm,也就是读取数据, 此处是在shiro.ini中读取的用户信息
securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
//3.SecurityUtils(全局安全管理器) , 给全局安全管理器设置安全管理器
SecurityUtils.setSecurityManager(securityManager);
//4.关键对象 subject主体
Subject subject = SecurityUtils.getSubject();
//5.创建令牌 请求的用户信息
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123456");
try {
System.out.println("认证状态: " + subject.isAuthenticated()); //未认证 false
//5.进行认证
subject.login(token);
System.out.println("认证状态: " + subject.isAuthenticated()); //已认证 true
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("未知用户异常");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("密码错误异常");
}
}
}
shiro真实做认证和授权的类
2 自定义realm域进行shiro认证 授权
2.1 自定义的realm
/**
* 自定义realm,继承AuthorizingRealm类,重写认证授权的具体方法,完成自定义认证授权
*/
public class MyRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("============================================");
//进行认证时候,shiro会把携带用户信息的token传递过来,可以从参数authenticationToken 中获取用户信息,
String principal = (String) authenticationToken.getPrincipal();//Principal主要的,也就是当前用户主体,得到用户名,可以直接转为String
System.out.println("登录用户信息 :" + principal); //打印 登录用户信息 :zhangsan
//可以将获取到的用户名 去查询自己的数据库 看看是否有此人信息,此处为查库,假设有
if ("zhangsan".equals(principal)) {
//源码中,最终进行用户名比较是在SimpleAccountRealm 中 方法 doGetAuthenticationInfo中进行的
/*参数解释:
参数principal: 数据库中的用户名
参数credentials: 数据库中的用户密码
realmNmae: 自定义的realm名字,可以通过父类方法getName()直接获取到
SimpleAuthenticationInfo 就会进行 登录用户 与数据库中的用户信息进行校验
*/
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo("zhangsan","123456",this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
2.2 在测试用使用自定的 realm进行认证 ,当调用subject.login时,会将用户信息传递到自定义的realm中进行认证校验
/**
* 通过自定义的realm进行shiro认证,也就是将realm设置成自定义的
*/
public class MyRealmAuthenticator {
public static void main(String[] args) {
//创建默认的安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//给安全管理器设置自定义的realm,也就是读取数据
securityManager.setRealm(new MyRealm());
//将此安全管理器交给安全管理器工具类管理
SecurityUtils.setSecurityManager(securityManager);
//安全管理器,获取当前认证用户主体
Subject subject = SecurityUtils.getSubject();
//通过用户名和密码生成shiro的token,这就是访问用户的信息,拿去和系统中的用户信息进行比较
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123456");
try {
//进行login认证校验
subject.login(token); //此处的token会传送到自定义的realm中进行与系统中的用户信息进行校验
System.out.println("认证状态: " + subject.isAuthenticated());
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("未知用户异常");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("密码错误异常");
}
}
}
3 shiro整合了校验的算法 MD5 + 加盐 + 加散次列(加盐的次数)
3.1 shiro中 MD5 简单使用演示
/**
* shiro中整合 MD5加密 测试
* 生成的都是 16进制32位长度的字符串
*/
public class shiro_MD5_test {
public static void main(String[] args) {
//简单对 123456 进行MD5加密
Md5Hash md5Hash = new Md5Hash("123456");
System.out.println("md5简单加密 : " + md5Hash);
//使用md5 + 盐 进行加密
Md5Hash md5_salt = new Md5Hash("123456", "my_salt");
System.out.println("md5加盐加密 : " + md5_salt);
//MD5 + salt + 散次列(盐次数)
Md5Hash md5_salt_times = new Md5Hash("123456", "my_salt", 5);
System.out.println("md5加盐加散次列 : " + md5_salt_times);
}
}
测试结果:
md5简单加密 : e10adc3949ba59abbe56e057f20f883e
md5加盐加密 : 622708d1cb1a66ca96b087344e56598d
md5加盐加散次列 : 95683f31ef383ecfe3d4d332ff762c5f
3.2 测试 设置realm设置MD5加密 对用户进行校验
3.2.1自定义realm
/**
* 自定义realm ,测试使用MD5 + 盐 + 散次列 进行校验
*/
public class Md5Realm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("-------------------------------------");
//进行认证时候,shiro会把携带用户信息的token传递过来,可以从参数authenticationToken 中获取用户信息,
String principal = (String) authenticationToken.getPrincipal(); //Principal主要的,也就是当前用户主体,得到用户名,可以直接转为String
System.out.println("登录用户信息 :" + principal);
//可以将获取到的用户名 去查询自己的数据库 看看是否有此人信息,此处为查库,假设有
if ("zhangsan".equals(principal)) {
//源码中,最终进行用户名比较是在SimpleAccountRealm 中 方法 doGetAuthenticationInfo中进行的
/*参数解释:
参数principal: 数据库中的用户名
参数credentials: 数据库中的用户密码
realmNmae: 自定义的realm名字,可以通过父类方法getName()直接获取到
SimpleAuthenticationInfo 就会进行 登录用户 与数据库中的用户信息进行校验
*/
//参数1:数据库用户名 参数2: 数据库md5 + salt + 散次列 后的密码 参数3:散次列 参数4:realm名字
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
"zhangsan",
"95683f31ef383ecfe3d4d332ff762c5f",
ByteSource.Util.bytes("my_salt"),
this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
3.2.2 用户认证测试
/**
* 在进行用户信息校验的时候,设置校验方式为MD5校验,可以设置散次列, 盐放在了realm中设置
*/
public class Md5MyRealmAuthenticator {
public static void main(String[] args) {
//创建默认的安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//给安全管理器设置自定义的realm,也就是读取数据
//创建自定义的Realm对象,为了后边设置 哈希凭证匹配器
Md5Realm md5Realm = new Md5Realm();
//设置 哈希凭证匹配器(加密方式) md5,设置散次列
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //哈希凭证匹配器
//使用算法
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
//加盐次数
hashedCredentialsMatcher.setHashIterations(5);
//自定义的realm设置 哈希凭证匹配器
md5Realm.setCredentialsMatcher(hashedCredentialsMatcher);
//设置安全管理器使用自定义的realm域
securityManager.setRealm(md5Realm);
//将此安全管理器交给安全管理器工具类管理
SecurityUtils.setSecurityManager(securityManager);
//安全管理器,获取当前认证用户主体
Subject subject = SecurityUtils.getSubject();
//通过用户名和密码生成shiro的token,这就是访问用户的信息,拿去和系统中的用户信息进行比较
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123456");
try {
//进行login认证校验
subject.login(token); //此处的token会传送到自定义的realm中进行与系统中的用户信息进行校验
System.out.println("认证状态: " + subject.isAuthenticated());
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("未知用户异常");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("密码错误异常");
}
}
}
4 shiro中授权 知识点
4.1 认证之后进行授权操作
基于md5 + 盐 + 散次列 进行认证之后的授权操作
4.1.1 自定的 realm
/**
* 自定义realm ,测试使用MD5 + 盐 + 散次列 进行校验 ,此处进行授权测试
* //认证是 new SimpleAuthenticationInfo 授权是 new SimpleAuthorizationInfo();
*/
public class Md5RealmAuthorizater extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("++++++++++++++++++++++进入了授权方法++++++++++++++++++++++++++++++++");
String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
System.out.println("当前用户信息 :" + primaryPrincipal);
//正常业务是通过用户的信息,(用户名)去数据库中查询用户的角色或者资源信息,然后进行校验
//将数据库中查询的权限信息赋予给用户对象
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//基于角色的权限控制
simpleAuthorizationInfo.addRole("admin");
simpleAuthorizationInfo.addRole("user");
//将数据库中查询的资源权限信息赋予给权限对象 资源:操作:对象 --> user:查询:01对象
simpleAuthorizationInfo.addStringPermission("user:*:01");
simpleAuthorizationInfo.addStringPermission("super:create");
return simpleAuthorizationInfo;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("-----------------进入了认证方法--------------------");
//进行认证时候,shiro会把携带用户信息的token传递过来,可以从参数authenticationToken 中获取用户信息,
String principal = (String) authenticationToken.getPrincipal(); //Principal主要的,也就是当前用户主体,得到用户名,可以直接转为String
System.out.println("登录用户信息 :" + principal);
//可以将获取到的用户名 去查询自己的数据库 看看是否有此人信息,此处为查库,假设有
if ("zhangsan".equals(principal)) {
//源码中,最终进行用户名比较是在SimpleAccountRealm 中 方法 doGetAuthenticationInfo中进行的
/*参数解释:
参数principal: 数据库中的用户名
参数credentials: 数据库中的用户密码
realmNmae: 自定义的realm名字,可以通过父类方法getName()直接获取到
SimpleAuthenticationInfo 就会进行 登录用户 与数据库中的用户信息进行校验
*/
//参数1:数据库用户名 参数2: 数据库md5 + salt + 散次列 后的密码 参数3:散次列 参数4:realm名字
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
"zhangsan",
"95683f31ef383ecfe3d4d332ff762c5f",
ByteSource.Util.bytes("my_salt"),
this.getName());
return simpleAuthenticationInfo;
}
return null;
}
}
4.1.2 进行授权测试 两种授权方式 : 01 基于角色的授权 02 基于资源权限的授权
/**
* shiro中进行简单的授权测试 , 此处是基于md5 + salt + 散次列 认证之后进行的授权
* 授权是在认证之后的,认证为true才可进行权限控制
* 分为基于角色的授权 和 基于资源权限的授权(资源标识符:操作:资源类型)
*/
public class Md5SimpleAuthorizater {
public static void main(String[] args) {
//创建默认的安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//给安全管理器设置自定义的realm,也就是读取数据
//创建自定义的Realm对象,为了后边设置 哈希凭证匹配器
Md5RealmAuthorizater md5RealmAuthorizater = new Md5RealmAuthorizater();
//设置 哈希凭证匹配器(加密方式) md5,设置散次列
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //哈希凭证匹配器
//使用算法
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
//加盐次数
hashedCredentialsMatcher.setHashIterations(5);
//自定义的realm设置 哈希凭证匹配器
md5RealmAuthorizater.setCredentialsMatcher(hashedCredentialsMatcher);
//设置安全管理器使用自定义的realm域
securityManager.setRealm(md5RealmAuthorizater);
//将此安全管理器交给安全管理器工具类管理
SecurityUtils.setSecurityManager(securityManager);
//安全管理器,获取当前认证用户主体
Subject subject = SecurityUtils.getSubject();
//通过用户名和密码生成shiro的token,这就是访问用户的信息,拿去和系统中的用户信息进行比较
UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123456");
try {
//进行login认证校验
subject.login(token); //此处的token会传送到自定义的realm中进行与系统中的用户信息进行校验
System.out.println("认证状态: " + subject.isAuthenticated());
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("未知用户异常");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("密码错误异常");
}
//认证完成,进行授权操作
if (subject.isAuthenticated()) {
//基于单个角色的权限控制
System.out.println("是否有此角色信息 :" + subject.hasRole("admin"));
//基于多角色权限控制,校验用户是否同时具有多个角色
System.out.println("是否同时具有多个角色 :" + subject.hasAllRoles( Arrays.asList("admin", "user")));
//是否有其中一个角色
boolean[] roles = subject.hasRoles(Arrays.asList("admin", "user", "super"));
for (boolean role : roles) {
System.out.println("是否具有某个角色 : " + role);
}
//基于权限的字符串的访问控制 资源标识符:操作:资源类型
System.out.println("资源权限" + subject.isPermitted("user:create:01")); //资源权限true
System.out.println("资源权限" + subject.isPermitted("super:update")); //资源权限false
//分别有那些权限
boolean[] Permittes = subject.isPermitted("user:create:01", "user:create:02"); //资源权限 : true 资源权限 : false
for (boolean permitte : Permittes) {
System.out.println("资源权限 : " + permitte);
}
//同时具有哪些资源权限
System.out.println("是否同时具有权限 : " + subject.isPermittedAll("user:create:01", "super:create:02")); //是否同时具有权限 : true
}
}
}
5 springboot整合shiro思路