获取源码和笔记地址:https://gitee.com/monologue_zsj/shiro.git
- Subject:主体
- 访问系统的用户,主体可以是用户、程序等,进行认证的都称为主体;
- Principal:身份信息
- 是主体(subject)进行身份认证的标识,标识必须具有唯一性,如用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)。
- credential:凭证信息
- 是只有主体自己知道的安全信息,如密码、证书等。
1、shiro-single
<!--Shrio依赖(maven 项目)-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.5.3</version>
</dependency>
#shiro.ini 模拟数据
[users]
xiaozhang=123
zhangsan=123456
lisi=789
1.1 测试认证
/**
* Created by Monologue_zsj on 2021/3/7 9:58
* Author:小脸儿红扑扑
* Description:测试认证
*/
public class TestAuthenticator {
public static void main(String[] args) {
//1、创建安全管理器
DefaultSecurityManager securityManager = new DefaultSecurityManager();
//2、给安全管理器设置Realm
securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
//3、SecurityUtils 给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(securityManager);
//4、关键对象 subject 主体
Subject subject = SecurityUtils.getSubject();
//5、创建令牌
UsernamePasswordToken token = new UsernamePasswordToken("xiaozhang", "123");
try {
System.out.println("认证状态========>" + subject.isAuthenticated());
subject.login(token); //用户认证
System.out.println("认证状态========>" + subject.isAuthenticated());
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("认证失败========> 用户名不存在...");
}catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("认证失败========> 密码错误...");
}
}
}
1.2 自定义Realm
/**
* Created by Monologue_zsj on 2021/3/7 10:43
* Author:小脸儿红扑扑
* Description:自定义Realm实现,将认证/授权的数据的来源转为数据库的实现
*/
public class CustomerRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//在token中获取用户名
String principal = (String) token.getPrincipal();
//根据身份信息使用jdbc/mybatis...查询相关数据库
if ("xiaozhang".equals(principal)) {
/**
* 参数1:返回数据库中正确的用户名
* 参数2:返回数据库中正确的密码
* 参数3:提供当前Realm的名字 this.getName()
*/
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principal, "123", getName());
return simpleAuthenticationInfo;
}
return null;
}
}
/**
* Created by Monologue_zsj on 2021/3/7 10:46
* Author:小脸儿红扑扑
* Description:使用自定义Realm
*/
public class TestCustomerRealmAuthenticator {
public static void main(String[] args) {
//创建SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//设置自定义Realm
defaultSecurityManager.setRealm(new CustomerRealm());
//给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
//通过安全工具类获取subject
Subject subject = SecurityUtils.getSubject();
//创建token
UsernamePasswordToken token = new UsernamePasswordToken("xiaozhang", "123");
try {
subject.login(token);
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("认证失败========> 用户名不存在...");
}catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("认证失败========> 密码错误...");
}
}
}
1.3 MD5加密
/**
* Created by Monologue_zsj on 2021/3/7 12:15
* Author:小脸儿红扑扑
* Description:MD5加密
*/
public class TestShiroMD5 {
public static void main(String[] args) {
//创建一个md5算法
// Md5Hash md5Hash = new Md5Hash();
// md5Hash.setBytes("123456".getBytes());
// String hex = md5Hash.toHex();
// System.out.println(hex);
//使用MD5
Md5Hash md5Hash = new Md5Hash("123456");
System.out.println(md5Hash.toHex());
//使用MD5 + salt 处理
Md5Hash md5Salt = new Md5Hash("123456", "X0*7ps");
System.out.println(md5Salt);
//使用MD5 + salt + hash散列(散列次数)
Md5Hash hash = new Md5Hash("123456", "X0*7ps", 1024);
System.out.println(hash);
}
}
/*
e10adc3949ba59abbe56e057f20f883e MD5
e99a0dee78d3c1f71609cead42047675 MD5 + salt
955224a95d4161ad8bd84f7ede979c02 MD5 + salt + hash
*/
Shiro认证对密码进行加密案例:
/**
* Created by Monologue_zsj on 2021/3/7 12:23
* Author:小脸儿红扑扑
* Description:使用自定义Realm加入 md5 + salt + hash
*/
public class CustomerMD5Realm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取身份信息
String principal = (String) token.getPrincipal();
//根据用户名查询数据库
if ("xiaozhang".equals(principal)) {
/**
* 参数1:数据库用户名
* 参数2:数据库md5 + salt之后的密码
* 参数3:注册时的随机盐
* 参数4:realm的名字
*/
return new SimpleAuthenticationInfo(principal,
"955224a95d4161ad8bd84f7ede979c02",
ByteSource.Util.bytes("X0*7ps"),
this.getName());
}
return null;
}
}
/**
* Created by Monologue_zsj on 2021/3/7 10:46
* Author:小脸儿红扑扑
* Description:使用自定义Realm
*/
public class TestCustomerMD5RealmAuthenticator {
public static void main(String[] args) {
//创建SecurityManager
DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
//注入Realm
CustomerMD5Realm realm = new CustomerMD5Realm();
//设置Realm使用hash凭证匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
//使用的算法
credentialsMatcher.setHashAlgorithmName("md5");
//散列的次数
credentialsMatcher.setHashIterations(1024);
realm.setCredentialsMatcher(credentialsMatcher);
//设置自定义Realm
defaultSecurityManager.setRealm(realm);
//给全局安全工具类设置安全管理器
SecurityUtils.setSecurityManager(defaultSecurityManager);
//通过安全工具类获取subject
Subject subject = SecurityUtils.getSubject();
//创建token,认证
UsernamePasswordToken token = new UsernamePasswordToken("xiaozhang", "123456");
try {
subject.login(token);
System.out.println("登录成功...");
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("认证失败========> 用户名不存在...");
}catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("认证失败========> 密码错误...");
}
}
}
1.4 授权
授权方式
- 基于角色的访问控制
-
RBAC(Role-Based Access Control)是以角色为中心进行访问控制
if(subject.hasRole("admin")) {
//操作什么资源
}
- 基于资源的访问控制
-
RBAC(Resource-Based Access Control)是以资源为中心进行访问控制
if(subject.isPermission("user:update:01")){ //资源实例
//对01用户进行修改
}
if(subject.isPermission("user:update:*")){ //资源类型
//对01用户进行修改
}
权限字符串(资源标识符:操作:资源实例标识符)
-
用户创建权限:user:create,或user:create:*
-
用户修改实例001权限:user:update:001
-
用户实例001的所有权限:user:*:001
/**
* Created by Monologue_zsj on 2021/3/7 12:23
* Author:小脸儿红扑扑
* Description:使用自定义Realm加入 md5 + salt + hash
*/
public class CustomerMD5Realm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
String primaryPrincipal = (String) principal.getPrimaryPrincipal();
System.out.println("身份信息(用户名)===============》" + primaryPrincipal);
//根据身份信息获取当前用户的角色信息,以及权限信息
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//将数据库中查询角色信息赋给权限对象
simpleAuthorizationInfo.addRole("admin");
simpleAuthorizationInfo.addRole("user");
//将数据库中查询权限信息赋值个给权限对象
simpleAuthorizationInfo.addStringPermission("user:*:01");
simpleAuthorizationInfo.addStringPermission("product:*:*");
return simpleAuthorizationInfo;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
...
}
}
/**
* Created by Monologue_zsj on 2021/3/7 10:46
* Author:小脸儿红扑扑
* Description:使用自定义Realm
*/
public class TestCustomerMD5RealmAuthenticator {
public static void main(String[] args) {
...
//认证的用户进行授权
if (subject.isAuthenticated()) { //认证成功
//基于角色的权限控制
System.out.println("hasRole:" + subject.hasRole("admin"));
System.out.println("__________________________________________________________________");
//基于多角色的权限控制
System.out.println("hasAllRoles:" + subject.hasAllRoles(Arrays.asList("admin", "user")));
System.out.println("__________________________________________________________________");
//是否具有其中一个角色
for (boolean role : subject.hasRoles(Arrays.asList("admin", "user", "super"))) {
System.out.println("hasRoles:" + role);
}
System.out.println("__________________________________________________________________");
//基于权限字符串的访问控制 资源标识符:操作:资源类型
System.out.println("isPermitted:" + subject.isPermitted("user:*:01"));
System.out.println("__________________________________________________________________");
//分别具有那些权限
for (boolean permitted : subject.isPermitted("user:*:01", "order:*:10")) {
System.out.println(permitted);
}
System.out.println("__________________________________________________________________");
//同时具有那些权限
System.out.println(subject.isPermittedAll("user:*:01", "product:*"));
}
}
}