您的位置:首页 > 其它

Shiro身份认证授权原理

2017-07-29 17:13 591 查看


shiro在应用程序中的使用是用Subject为入口的, 最终subject委托给真正的管理者ShiroSecurityMannager

Realm是Shiro获得身份认证信息和来源信息的地方(所以这里是我们实现的)我们只要继承他的实现类重写方法就好了,AuthorizingRealm

身份认证过程

自定义realm代码

public class myRealm  extends AuthorizingRealm  {
//realm的名称
@Override
public String getName() {
// TODO Auto-generated method stub
return "myRealm";
}
//验证token是否是有效的token
@Override
public boolean supports(AuthenticationToken arg0) {
// TODO Auto-generated method stub
return arg0 instanceof UsernamePasswordToken;
}
//授权获得用户权限信息的方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addRole("321");
info.addRole("3332");
info.addStringPermission("333");
info.addStringPermission("555");
info.addObjectPermission(new WildcardPermission("44"));
// TODO Auto-generated method stub
return info;
}
//认证获取用户身份信息的方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken loginToken=(UsernamePasswordToken)token;
String password=new String(loginToken.getPassword());
System.out.println(password);
System.out.println(loginToken.getUsername());
if(loginToken.getUsername()=="zhang"&&password.equals("123")){

}else{
throw new IncorrectCredentialsException();
}
// TODO Auto-generated method stub
SimpleAuthenticationInfo info= new SimpleAuthenticationInfo(loginToken.getUsername(),password,getName());
return info;
}

}


  

doGetAuthorizationInfo方法是进行用户授权的时候调用的方法 用户获得当前用户的授权信息 先不管他
doGetAuthenticationInfo是当我们调用subject.login进行认证的方法 这个方法的参数token就是我们subject.login调用的
这里面我们就可以查询数据库对用户名和密码进行认证
如果认证成功将用户信息封装成SimpleAuthenticationInfo
认证失败根据几种情况抛出异常,常见的如:
DisabledAccountException(禁用的帐号)、LockedAccountException(锁定的帐号)
UnknownAccountException(错误的帐号)
ExcessiveAttemptsException(登录失败次数过多)、IncorrectCredentialsException (错误的凭证)
ExpiredCredentialsException(过期的凭证)等

shiro.ini配置

#声明一个realm
myRealm1=com.liqiang.realm.myRealm
#这里就是我们注入realm的地方
securityManager.realms=$myRealm1


实现身份认证的代码

@Test
public void testHelloworld() {
//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory<org.apache.shiro.mgt.SecurityManager> factory =
new IniSecurityManagerFactory("classpath:shiro.ini");
//2、得到SecurityManager实例 并绑定给SecurityUtils
org.apache.shiro.mgt.SecurityManagersecurityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
//3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");

try {
//4、登录,即身份验证
subject.login(token);
} catch (AuthenticationException e) {
//5、身份验证失败
}

subject.logout();
}


上面我们调用sbuject.login(token) 这个token封装了前端用户输入的用户名和密码



授权验证

当我们通过subject.isPermitted("user:update") 当我们判断当前用户是否拥有user:update这个权限代码的时候

会调用我们ream的 doGetAuthorizationInfo 方法获得授权信息。我们在这里面就是根据用户信息查询数据将认证信息封装

SimpleAuthorizationInfo 返回回去



//授权获得用户权限信息的方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addRole("321");
info.addRole("3332");
info.addStringPermission("333");
info.addStringPermission("555");
info.addObjectPermission(new WildcardPermission("44"));
// TODO Auto-generated method stub
return info;
}


这里通过查询数据库知道用户有321 332 这2个角色 和 333 555 44 这几个权限

WildcardPermission 这个又是什么意思呢。。通过addStringPermission  默认是用Permission的实现类封装的 如果我们又定义就用我们的封装 没有定义就用默认的WildcardPermission
最终将他们保存到一个集合里面
如:


public class MyPermission implements Permission {

String permissionCode;
public MyPermission(String name) {
permissionCode=name;
}

@Override
public boolean implies(Permission permission) {
//自定义比较
// TODO Auto-generated method stub
return false;
}

}


当我们调用subject.isPermitted("user:update")会调用将指令传达给

SecurityManager

SecurityManager再将指令传达给授权管理类Authorizer

Authorizer会通过reaml获得授权信息SimpleAuthorizationInfo
如果我们返回的授权信息拥有角色 会调用RolePermissionResolver实现类的方法 将角色的权限追加到SimpleAuthorizationInfo(默认是没有实现的)
如:


public class MyRolePermissionResolver  implements RolePermissionResolver{

@Override
public Collection<Permission> resolvePermissionsInRole(String roleString) {
// TODO Auto-generated method stub
return Arrays.asList((Permission)new MyPermission("menu:*"));
}


这里面应该是根据角色查询权限

最终 遍历SimpleAuthorizationInfo的权限信息 (我们的权限信息都封装Permission接口实现类 调用implies方法进行比较 如果比较成功返回true 表示授权通过)自定义Permission的好处就是我们可以自定义匹配规则

注入自定义Permission和RolePerminssion的配置

[main]
authorizer=org.apache.shiro.authz.ModularRealmAuthorizer
securityManager.authorizer=$authorizer
#自定义rolePermissionResolver
rolePermissionResolver=com.liqiang.permissionResolver.MyRolePermissionResolver
authorizer.rolePermissionResolver=$rolePermissionResolver
securityManager.authorizer=$authorizer
permissionResolver=com.liqiang.permissionResolver.MyPermissionResolver
authorizer.permissionResolver=$permissionResolver
#声明一个realm
myRealm1=com.liqiang.realm.myRealm
#指定securityManager的realms实现
securityManager.realms=$myRealm1


PS:好记性不如烂笔头 希望自己回头来看一下就能回忆起来

学习文章:http://jinnianshilongnian.iteye.com/blog/2018398
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: