Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框架。
Shiro 是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加
密。
权限:一般指根据系统设置的安全策略或者安全规则,用户可以访问而且只能访问自己被授权
的资源,不多不少。权限管理几乎出现在任何系统里面,只要有用户和密码的系统。
权限管理在系统中一般分为:访问权限和数据权限。
认证:身份认证,就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和密码,看其是否与系统中存储的该用户的用户名和密码一致,来判断用户身份是否正确。例如:密码登录,手机短信验证、三方授权等。
认证流程:
授权:即访问控制,控制谁能访问哪些资源。主体进行身份认证后,系统会为其分配对应的权限,当访问资源时,会校验其是否有访问此资源的权限。
在Shiro中,采取的是先鉴权,在授权,只有在需要鉴权的时候,Shiro才会去调用相关方法去完成一次次授权操作;
简单来说,鉴权就是用户通过认证后访问资源时,判断判断是否具有访问资源的能力的过程。
通过Shiro实现基于内存形式的认证和授权(不从库中查数据)。
编码与解码:
Shiro提供了base64和16进制字符串编码/解码的API支持,方便一些编码解码操作。
Shiro内部的一些数据的【存储/表示】都使用了base64和16进制字符串.
散列算法:
散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据。shiro支持的散列算法:Md2Hash、Md5Hash、Sha1Hash、Sha256Hash、Sha384Hash、Sha512Hash。
以SHA-1为例的加密工具类:
/**
* @author 杨树林
* @version 1.0
* @since 16/8/2023
*/
public class DigestUtil {
//算法方式
private static final String SHA1 = "SHA-1";
public static final String SHA256 = "SHA-256";
//加密次数
public static final Integer Counts =369;
/**
* @Description show
* @param input 需要散列字符串
* @param salt 盐字符串
* @return
*/
public static String show(String input,String salt){
return new SimpleHash(SHA256,input,salt,Counts).toString();
}
/**
* @Description 随机获得salt字符串
* @return
*/
public static String generateSalt(){
SecureRandomNumberGenerator randomNumberGenerator =new SecureRandomNumberGenerator();
return randomNumberGenerator.nextBytes().toHex();
}
/**
* @Description 生成密码字符密文和salt密文
* @param
* @return
*/
public static Map<String,String> entryptPassword(String passwordPlain){
Map<String,String> map = new HashMap<>();
String salt =generateSalt();
String password = show(passwordPlain,salt);
map.put("salt",salt);
map.put("明文password",passwordPlain);
map.put("密文密码",password);
return map;
}
}
Shiro中的Realm接口下有三个实现类:
最常用的是支持授权的AuthorizingRealm;
2.1在resource目录下创建shiro.ini文件,并配置Realm的信息,用于告诉SecurityManager权限管理器Realm的信息;
[main]
MyClass=com.apesource.shiro.MyRealm
securityManager.realms=$MyClass
2.2自定义MyRealm类,继承AuthorizingRealm 实现类
public class MyRealm extends AuthorizingRealm {
//告诉shiro使用的散列算法
public MyRealm() {
//指定密码的算法方式sha256
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(DigestUtil.SHA256);
//指定加密次数
hashedCredentialsMatcher.setHashIterations(DigestUtil.Counts);
//使用父层方法使匹配生效
setCredentialsMatcher(hashedCredentialsMatcher);
}
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("进入doGetAuthorizationInfo鉴权方法");
//1.获取安全数据 username
String username = (String) principalCollection.getPrimaryPrincipal();
//2.通过安全数据查询库。。。。
//通过认证传递的安全数据,去数据库查询角色以及权限,实现授权
List<String> perms = new ArrayList<>();
perms.add("user:save");
perms.add("user:update");
perms.add("user:delete");
perms.add("user:find");
List<String> roles = new ArrayList<>();
roles.add("role1");
roles.add("role2");
//3.构造返回
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//4.设置权限集合
info.addStringPermissions(perms);
//设置身份集合
info.addRoles(roles);
return info;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
//获取用户输入的密码
String username = token.getUsername();
//模拟数据库查询用户信息信息
ServiceImpl service = new ServiceImpl();
Map<String, String> map = service.findPasswordByLoginName(username);
if(map==null){
throw new UnknownAccountException("账户不存在");
}
System.out.println(map);
String salt = map.get("salt");
System.out.println(salt);
String password = map.get("密文密码");//密文密码
return new SimpleAuthenticationInfo(username,password, ByteSource.Util.bytes(salt),"MyRealm");
}
}
2.3构造业务层,提供比对数据(模拟从库中查询数据)
public interface Service {
Map<String,String> findPasswordByLoginName(String loginName);
}
实现类:
public class ServiceImpl implements Service {
@Override
public Map<String, String> findPasswordByLoginName(String loginName) {
//模拟库中查询对象
//1.获取dao对象
//2.调用dao方法(按照用户名称查询用户信息,匿名密码)
if(loginName.equals("yangshulin")){
Map<String, String> map = DigestUtil.entryptPassword("123456");
return map;
}
return null;
}
}
public class Test1 {
@Test
public void login(){
//导入INI配置创建工厂
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//工厂构建安全管理器
SecurityManager securityManager = factory.getInstance();
//使用工具生效安全管理器
SecurityUtils.setSecurityManager(securityManager);
//使用工具获得subject主体
Subject subject = SecurityUtils.getSubject();
//构建账号密码
UsernamePasswordToken token = new UsernamePasswordToken("yangshulin","1223456");
subject.login(token);
//打印登录信息
System.out.println("登录结果:"+subject.isAuthenticated());
//鉴权
System.out.println(subject.hasRole("role1"));
System.out.println(subject.hasRole("role2"));
System.out.println(subject.isPermitted("user:save"));
System.out.println(subject.isPermitted("user:update"));
System.out.println(subject.isPermitted("user:find"));
}
}