Realm
SecuritManager(安全管理器)进行安全认证需要通过Realm获取用户权限数据
Realm也是一个接口,有多种实现:
1、将用户的权限信息写到配置文件
2、将用户的权限信息存储到数据库
Realm
从配置文件或者数据库等读取用户的权限信息
而Shiro自己封装的Realm只能从配置文件读取信息,而用户的认证和授权信息一般存储在关系型数据库中,方便我们维护相关信息。基于这一点,我们可以自定义Realm,下面来分析一下。
自定义Realm-继承 AuthorizingRealm
你要问我为什么要继承AuthorizingRealm?我是不会告诉你的,来看下图继承关系。
可以看出shiro框架所封装好的方法是new IniRealm(“classpath:xxxx.ini”);
那么,我们下面通过几张图来扒一扒它的"祖宗"。
那么相信你现在懂得为什么要继承AuthorizingRealm了。
现在我们就进行编写自定义的Realm类。
public class ShiroRealm extends AuthorizingRealm {
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
}
自定义Realm-认证实现
编写实体类
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
}
编程实现认证的自定义类
public class ShiroRealm extends AuthorizingRealm {
/*
登录认证
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
System.out.println("登录认证……");
//获取用户输入的用户名
String username = token.getUsername();
//获取用户输入的密码
String password = new String(token.getPassword());
//根据用户名去数据库中查询对应的用户信息
User user = new User("zhangsan", "123456");
if (!user.getUsername().equals(username)) {
throw new UnknownAccountException("用户名有误");
}
if (!user.getPassword().equals(password)) {
throw new CredentialsException("密码有误");
}
System.out.println("认证成功");
//创建简单认证信息对象
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), super.getName());
return info;
}
/*
授权
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("授权……");
return null;
}
}
你要问我为什么创建认证信息对象按照下面这种写法,这次我真的不会告诉你,只会告诉你,去看看一个父类子类之间的继承实现关系,你会明白的。
//创建简单认证信息对象
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), super.getName());
看下我们的工具类
public class ShiroUtil {
static {
//1.初始化shiro的安全管理器
DefaultSecurityManager securityManager=new DefaultSecurityManager();
//2.设置用户的权限信息到安全管理器
// Realm realm=new IniRealm("classpath:shiro.ini");
Realm realm=new ShiroRealm();
securityManager.setRealm(realm);
//3.使用SecurityUtils将securityManager设置到运行环境中
SecurityUtils.setSecurityManager(securityManager);
}
public static Subject login(String name,String password){
//4.创建一个Subject实例,该实例认证要使用上面创建的securityManager进行
Subject subject=SecurityUtils.getSubject();
//5.创建token令牌,记录用户认证的身份和凭证即证号和密码
UsernamePasswordToken token=new UsernamePasswordToken(name,password);
//6.主体要进行登录,登录的时候进行认证的检查
subject.login(token);
System.out.println("用户认证状态:"+subject.isAuthenticated());
return subject;
}
}
看下我们的测试类
public class ShiroTest {
@Test
public void test(){
Subject subject= ShiroUtil.login("zhangsan","123456");
}
}
测试一下吧
可以看出,这时候运行的Realm便是我们自定义的类了。
自定义Realm-授权实现
对ShiroRealm类进行修改
public class ShiroRealm extends AuthorizingRealm {
/*
登录认证
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
System.out.println("登录认证……");
//获取用户输入的用户名
String username = token.getUsername();
//获取用户输入的密码
String password = new String(token.getPassword());
//根据用户名去数据库中查询对应的用户信息
User user = new User("zhangsan", "123456");
if (!user.getUsername().equals(username)) {
throw new UnknownAccountException("用户名有误");
}
if (!user.getPassword().equals(password)) {
throw new CredentialsException("密码有误");
}
System.out.println("认证成功");
//创建简单认证信息对象
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(token.getPrincipal(), token.getCredentials(), super.getName());
return info;
}
/*
授权
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取主身份信息
String username=principalCollection.getPrimaryPrincipal().toString();
/*
简单授权信息对象,对象中包含用户的角色和权限信息
*/
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//模拟从数据库获取当前用户的角色 通过用户名查询该用户拥有的角色名称
Set<String>roleNameSet=new HashSet<String>();
roleNameSet.add("系统管理员");
roleNameSet.add("系统运维");
//模拟从数据库获取当前用户的角色 通过用户名查询该用户拥有的权限名称
Set<String>permissionNameSet=new HashSet<String>();
permissionNameSet.add("sys:user:list"); //模拟查看列表
permissionNameSet.add("sys:user:info"); //模拟查看用户详情
permissionNameSet.add("sys:user:create"); //模拟创建用户
permissionNameSet.add("sys:user:update"); //模拟修改用户
permissionNameSet.add("sys:user:delete"); //模拟删除用户
info.addRoles(roleNameSet);
info.addStringPermissions(permissionNameSet);
System.out.println("授权完成");
return info;
}
}
对测试类进行修改
public class ShiroTest {
@Test
public void test(){
//登录认证
Subject subject= ShiroUtil.login("zhangsan","123456");
//授权资源检查
//模拟当前用户点击了“新增用户按钮”,检查该用户时候是否新增用户……等等的权限
System.out.println("检查该用户是否拥有新增用户的权限"+subject.isPermitted("sys:user:create"));
System.out.println("检查该用户是否拥有删除用户的权限"+subject.isPermitted("sys:user:delete"));
System.out.println("检查该用户是否拥有喜欢某某某的权限"+subject.isPermitted("你还在么love?true:false"));
System.out.println("----------------------------------------------");
System.out.println("检查系统是否有系统管理员角色"+subject.hasRole("系统管理员"));
System.out.println("检查系统是否有系统运维角色"+subject.hasRole("系统运维"));
System.out.println("检查系统是否有haosy角色"+subject.hasRole("haosy"));
//退出系统
subject.logout();
}
}
测试
上文链接:https://haosy.blog.csdn.net/article/details/103612243
下午链接: https://haosy.blog.csdn.net/article/details/103645878
Shiro系列专题链接:https://blog.csdn.net/qq_43518645/category_9604248.html
2019/12/20学习记录。
来源:CSDN
作者:爱猫狗的小郝
链接:https://blog.csdn.net/qq_43518645/article/details/103635750