Apache Shiro 是Java 的一个安全框架。Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE 环境,也可以用在JavaEE 环境。Shiro 可以帮助我们完成:认证【登陆】、授权【权限】、加密【密码】、会话管理、与Web 集成、缓存等。
securityManager: 安全管理 它是核心组件。
Authenticator: 认证器
Authorizer: 授权器。
Realm: 理解为和数据库交互的一个组件。使用InitRealm—读取ini文件的内容。
(1)引入shiro-core的依赖
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-coreartifactId>
<version>1.7.0version>
dependency>
(2)创建一个ini文件 好比数据库 必须叫 users表示用户表
#表示用户表 存放着账户和密码
[users]
zs=111
ls=222
(3)测试
退出登录 :subject.logout();
判断当前用户是否认证成功:subject.isAuthenticated()
public static void main(String[] args) {
// 1.得到securityManager对象
DefaultSecurityManager securityManager = new DefaultSecurityManager();
// 2.设置securityManager管理的realm对象
securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
// 3.把securityManager绑定到securityManager
SecurityUtils.setSecurityManager(securityManager);
// 4.获取Subject对象
Subject subject = SecurityUtils.getSubject();
// 封装账户和密码
UsernamePasswordToken token = new UsernamePasswordToken("zs", "111");
try {
// 5.执行认证功能
subject.login(token);
System.out.println("账户和密码正确");
} catch (Exception e){
e.printStackTrace();
System.out.println("账户和密码错误");
}
// isAuthenticated判断当前的用户是否被认证
System.out.println("是否认证成功"+subject.isAuthenticated());
// 退出登录
subject.logout();
// isAuthenticated判断当前用户是否认证成功
System.out.println("是否认证成功"+subject.isAuthenticated());
}
首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;
SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 / 抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。
(1)在ini文件中
#表示用户表 存放着账户和密码
[users]
zs=111,admin
ls=222,role1
#表示角色表 包含角色的名称 角色具有的权限
[roles]
admin=user:query,user:delete,user:update,user:insert
role1=user:query
role2=user:query,user:update
role3=user:export
(2)测试授权,注意认证之后,再进行授权
当前认证后的用户是否具有user:query:subject.isPermitted(“user:query”)
当前认证后的用户是否具有多个权限:subject.isPermittedAll(“user:query”,“user:export”)
部分测试代码:
// 授权
System.out.println("当前认证后的用户是否具有user:query:"+subject.isPermitted("user:query"));
System.out.println("当前认证后的用户是否具有多个权限:"+subject.isPermittedAll("user:query","user:export"));
}
完整测试代码:
// 1.得到securityManager对象
DefaultSecurityManager securityManager = new DefaultSecurityManager();
// 2.设置securityManager管理的realm对象
securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
// 3.把securityManager绑定到securityManager
SecurityUtils.setSecurityManager(securityManager);
// 4.获取Subject对象
Subject subject = SecurityUtils.getSubject();
// 封装账户和密码
UsernamePasswordToken token = new UsernamePasswordToken("zs", "111");
try {
// 5.执行认证功能
subject.login(token);
System.out.println("账户和密码正确");
} catch (Exception e){
e.printStackTrace();
System.out.println("账户和密码错误");
}
// isAuthenticated判断当前的用户是否被认证
System.out.println("是否认证成功"+subject.isAuthenticated());
/*// 退出登录
subject.logout();
// isAuthenticated判断当前用户是否认证成功
System.out.println("是否认证成功"+subject.isAuthenticated());*/
// 授权
System.out.println("当前认证后的用户是否具有user:query:"+subject.isPermitted("user:query"));
System.out.println("当前认证后的用户是否具有多个权限:"+subject.isPermittedAll("user:query","user:export"));
**注意:**上面这些代码都是ini数据,实际开发肯定通过数据库进行的判断。
根据iniRealm创建自己的realm类,该类中就可以写自己连接数据库的内容。
创建MyRealm继承AuthorizingRealm,并重写doGetAuthorizationInfo和doGetAuthenticationInfo的方法
自己创建MyRealm类
绑定权限 SimpleAuthorizationInfo
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addStringPermissions(permission);
SimpleAuthenticationInfo类中的三个参数代表的意思:
Object principal,账号 可以被登录成功后获取,还可以传给授权的方法
Object credentials,从数据库中查询的密码
String realmName 当前realm的名称
认证
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassWord(),this.getName());
this.getName()表示调用父类的方法
package com.myrealm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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.List;
/**
* @author : 小峥
* @date : 2021/4/5 0:46
* @description:
*/
public class MyRealm extends AuthorizingRealm {
/* @AutoWird
private UserService userService;*/
private UserService userService = new UserService();
// 当执行授权时调用该方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User) principalCollection.getPrimaryPrincipal();
System.out.println("授权方法的执行"+user);
// 根据用户id擦混该用户具有的权限码
List<String> permission=userService.findPermissionById(user.getId());
// 绑定权限
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addStringPermissions(permission);
return info;
}
//当执行认证功能时调用该方法 认证时捕获异常
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("认证方法的执行");
// 得到账户 唯一的标识
String loginName = authenticationToken.getPrincipal().toString();
// System.out.println("你登录的账户值为:" + loginName);
// 调用service中的方法 根据用户名查询用户信息
User user = userService.findByLoginName(loginName);
if (user!=null){
// Object principal,账号 可以被登录成功后获取,还可以传给授权的方法
// Object credentials,从数据库中查询的密码
// String realmName 当前realm的名称
// SimpleAuthenticationInfo info = new SimpleAuthenticationInfo("hhhhhhh",user.getPassWord(),this.getName());
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassWord(),this.getName());
return info;
}
return null;
}
}
service层
public class UserService {
public User findByLoginName(String loginName) {
switch (loginName) {
case "admin":
return new User(1, "admin", "111", "管理员");
case "zs":
return new User(2, "zzz", "222", "张三");
case "ls":
return new User(3, "lll", "333", "李四");
default:
return null;
}
}
public List<String> findPermissionById(int id) {
List<String> list=new ArrayList<>();
if (id==1){
list.add("user:query");
list.add("user:delete");
list.add("user:update");
list.add("user:insert");
}else if (id==2){
list.add("user:query");
}else if (id==3){
list.add("user:delete");
list.add("user:update");
}
return list;
}
}
测试类
public class Demo {
public static void main(String[] args) {
// 得到SecurityManager对象
DefaultSecurityManager securityManager = new DefaultSecurityManager();
// 设置securityManager管理的realm对象
MyRealm myRealm = new MyRealm();
securityManager.setRealm(myRealm);
// 把securityManager绑定到SecurityUtilss
SecurityUtils.setSecurityManager(securityManager);
// 获取subject对象
Subject subject = SecurityUtils.getSubject();
// 封装账户和密码
UsernamePasswordToken token=new UsernamePasswordToken("zs","222");
subject.login(token);
Object principal = subject.getPrincipal();
System.out.println(principal);
// 认证-->登录
System.out.println("认证成功:"+subject.isAuthenticated());
// 只有认证之后才能执行MyRealm中的认证方法
System.out.println("查询权限:"+subject.isPermittedAll("user:query"));
}
}