认证流程
1. 首先调用Subject.login(token)进行登录,其会自动委托给Security Manager,调用之前必须通过
SecurityUtils. setSecurityManager()设置;
2. SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;
3. Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实
现;
4. Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认
ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证;
5. Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份
验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。
授权流程
1. 首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager,而SecurityManager接着会委托
给Authorizer;
2. Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”),其首先会通过PermissionResolver
把字符串转换成相应的Permission实例;
3. 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限;
4. Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给
ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted/hasRole会返回true,否则返回false表示
授权失败。
1.自定义realms 类
必须继承 AuthorizingRealm 抽象类
package com.zhao;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义realms 对象
* 继承 AuthorizingRealm
*/
public class RealmDemo extends AuthorizingRealm {
/**
* 设置 RealmDemo 名字 ,自定义realms 对象 过多时避免重复
* @param name
*/
@Override
public void setName(String name) {
super.setName("realmDemo");
}
/**
* 授权
* 获取到用户的授权数据(用户的权限数据)
* 根据认证的用户 获取到他的权限信息
* @param principals 包含了所有的已认证的安全数据
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println(" 授权 AuthorizationInfo ");
//1.获取安全数据 username ,有可能是用户id
String primaryPrincipal = (String)principals.getPrimaryPrincipal();
//2.根据 username 或者id查询用户
//3.查询用户的角色 和权限信息
//权限
List<String> perms =new ArrayList<>();
perms.add("user:save");
perms.add("user:find");
//角色
List<String> roles =new ArrayList<>();
roles.add("ordinary");
roles.add("admin");
//4.构造返回
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
//设置权限集合
info.addStringPermissions(perms);
//设置角色集合
info.addRoles(roles);
return info;
}
/**
* 认证
* 根据用户名密码进行登录,登录之后将用户数据进行保存
* 认证的目的,比较用户名和密码是否与数据库中的一致
* 将安全数据存入到shiro进行保管
* @param authenticationToken 登录构造的 UsernamePasswordToken
* @return AuthenticationInfo 授权数据
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println(" 认证 AuthenticationInfo ");
//1. 构造 UsernamePasswordToken
UsernamePasswordToken uptoken=(UsernamePasswordToken)authenticationToken;
//2.获取输入的用户名密码
String username = uptoken.getUsername();
String password = new String(uptoken.getPassword());
//3.根据用户名查询数据
//4.比较密码和数据库中的密码是否一致(密码可能需要加密)
if(username.equals("张三")&&password.equals("123456")){
//5.成功 向 shiro存入数据
/**
* *@param principal与指定领域关联的“primary”主体。 安全数据
* *@param credentials验证给定主体的凭据。 密码
* *@param realmName从中获取主体和凭据的域。 当前realm 名称 getName() 获取到的是当前realm的名称 ,他的父类方法
*/
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username,password,getName());
return simpleAuthenticationInfo;
}else {
//6.失败 返回null 或者抛出 自定义的异常
return null;
}
}
}
自定义realm类
2.配置文件
[main]
permRealm=com.zhao.RealmDemo
#注册realm到securityManager
securityManager.realms=$permRealm
View Code
3.测试
package com.zhao.shiro.test;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Before;
import org.junit.Test;
public class ShiroTest3 {
@Before
public void init(){
// 1.根据配置文件shiroDemo.ini 文件 创建 SecurityManagerFactor
Factory<SecurityManager> factory= new IniSecurityManagerFactory("classpath:shiroDemoRealm.ini");
//2.通过工厂获取SecurityManager
SecurityManager securityManager = factory.getInstance();
//* 3.将SecurityManager绑定到当前运行环境
SecurityUtils.setSecurityManager(securityManager);
}
/**
* 测试用户登录
* 用户认证
* 1.根据配置文件shiroDemo.ini 文件 创建 SecurityManagerFactor
* 2.通过工厂获取SecurityManager
* 3.将SecurityManager绑定到当前运行环境
* 4.从当前环境中构造subject
* 5.构造shiro登陆的数据
* 6.主题登录
*/
@Test
public void login1(){
//* 4.从当前环境中构造subject
Subject subject = SecurityUtils.getSubject();
// * 5.构造用户认证的数据
// String userName="lisi";
// String password = "10086";
String userName="张三";
String password = "123456";
UsernamePasswordToken token =new UsernamePasswordToken(userName,password);
// * 6.主题登录
//执行 login1--》realm 域中的认证方法
subject.login(token);
//登录之后完成授权 ,是否具有某个角色
System.out.println(subject.hasRole("admin")); //是否有admin 这个角色
System.out.println(subject.hasRole("root")); //是否有root 这个角色
System.out.println(subject.isPermitted("user:save"));// 是否有 user:save 这个权限
}
}
View Code