简介
Shiro 是当下常见的安全框架,主要用于用户验证和授权操作。
如同 spring security 一样都是是一个权限安全框架,但是与Spring Security相比,在于他使用了和比较简洁易懂的认证和授权方式。
Shiro的核心组件:
- Subject :当前用户的操作
- SecurityManager:用于管理所有的Subject
- Realms:用于进行权限信息的验证
Subject:即当前用户,在权限管理的应用程序里往往需要知道谁能够操作什么,谁拥有操作该程序的权利,shiro中则需要通过Subject来提供基础的当前用户信息,Subject 不仅仅代表某个用户,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。
SecurityManager:即所有Subject的管理者,这是Shiro框架的核心组件,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。
Realms:Realms则是用户的信息认证器和用户的权限人证器,我们需要自己来实现Realms来自定义的管理我们自己系统内部的权限规则。
实现方式
在shiro的用户权限认证过程中其通过两个方法来实现:
1、Authentication:是验证用户身份的过程。
2、Authorization:是授权访问控制,用于对用户进行的操作进行人证授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。
创建Shiro项目
使用IDEA创建maven项目,在pom.xml中添加依赖:
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.6.1</version> </dependency>
使用shiro
Shiro提供了一个通用的方案通过 INI 进行配置 ,当然也可以通过XML,YMAL,JSON等进行配置。
在resource目录下面,创建一个shiro.ini的文件。内容如下:
#定义用户 [users] #用户名 zhang3 密码是 12345, 角色是 admin zhang3 = 12345,admin #用户名 li4 密码是 abcde, 角色是 产品经理 li4 = abcde,productManager #定义角色 [roles] #管理员什么都能做 admin = * #产品经理只能做产品管理 productManager = addProduct,deleteProduct,editProduct,updateProduct,listProduct #订单经理只能做产品管理 orderManager = addOrder,deleteOrder,editOrder,updateOrder,listOrder
- 创建User对象
package cn.jp.shiro.pojo; /** * @author JP * @title: User * @projectName studyShiro * @description:准备用户类,存储账户和密码 * * @date 2019/2/22 00229:18 */ public class User { private String name; private String password; @Override public String toString() { return "User{" + "name='" + name + '\'' + ", password='" + password + '\'' + '}'; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
- 创建一个TestShiro测试类
package cn.jp.shiro.test; import java.util.ArrayList; import java.util.List; import cn.jp.shiro.pojo.User; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; 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; /** * @author JP * @title: TestShiro * @projectName studyShiro * @description:测试shiro安全框架 * @date 2019/2/22 00229:22 */ public class TestShiro { public static void main(String[] args) { User zhang3 = new User(); zhang3.setName("zhang3"); zhang3.setPassword("12345"); User li4 = new User(); li4.setName("li4"); li4.setPassword("abcde"); User wang5 = new User(); wang5.setName("wang5"); wang5.setPassword("wrongpassword"); List<User> users = new ArrayList<>(); users.add(zhang3); users.add(li4); users.add(wang5); //角色们 String roleAdmin = "admin"; String roleProductManager = "productManager"; String orderManager = "orderManager"; List<String> roles = new ArrayList<>(); roles.add(roleAdmin); roles.add(roleProductManager); roles.add(orderManager); //权限们 String permitAddProduct = "addProduct"; String permitAddOrder = "addOrder"; String permitDeleteProduct = "deleteProduct"; List<String> permits = new ArrayList<>(); permits.add(permitAddProduct); permits.add(permitAddOrder); permits.add(permitDeleteProduct); //登录每个用户 for (User user : users) { if (login(user)) { System.out.printf("%s \t成功登陆,用的密码是 %s\t %n", user.getName(), user.getPassword()); } else { System.out.printf("%s \t成功失败,用的密码是 %s\t %n", user.getName(), user.getPassword()); } } System.out.println("------- 分割线------"); //判断能够登录的用户是否拥有某个角色 for (User user : users) { for (String role : roles) { if (login(user)) { if (TestShiro.hasRole(user, role)) { System.out.printf("%s\t 拥有角色: %s\t%n", user.getName(), role); } else { System.out.printf("%s\t 不拥有角色: %s\t%n", user.getName(), role); } } } } System.out.println("------- 分割线------"); for(User user:users){ for(String permit:permits){ if(login(user)){ if(isPermitted(user,permit)){ System.out.printf("%s\t 拥有权限: %s\t%n",user.getName(),permit); }else{ System.out.printf("%s\t 不拥有权限: %s\t%n",user.getName(),permit); } } } } } /** * @return * @Author jp * @Description //TODO 用户拥有角色 * @Date 9:37 2019/2/22 0022 * @Param **/ public static boolean hasRole(User user, String role) { Subject subject = getSubject(user); return subject.hasRole(role); } /** * @return * @Author jp * @Description //TODO 判断是否拥有权限 * @Date 9:39 2019/2/22 0022 * @Param **/ public static boolean isPermitted(User user, String permit) { Subject subject = getSubject(user); return subject.isPermitted(permit); } /** * @Author jp * @Description //TODO * @Date 10:21 2019/2/22 0022 * @Param * @return **/ private static Subject getSubject(User user) { //加载配置文件,获取工厂 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //获取安全管理实例 SecurityManager sm = factory.getInstance(); //将安全管理sui者放入全局对象 SecurityUtils.setSecurityManager(sm); //全局对象通过安全管理者生成Subject对象 Subject subject = SecurityUtils.getSubject(); return subject; } /** * @return * @Author jp * @Description //TODO 判断用户是否登录 * @Date 9:35 2019/2/22 0022 * @Param **/ private static boolean login(User user) { Subject subject = getSubject(user); //如果已经登录,退出 if (subject.isAuthenticated()) subject.logout(); //封装用户数据 UsernamePasswordToken token = new UsernamePasswordToken(user.getName(), user.getPassword()); try { //将用户数据token,最终传递到Realm中进行对比 subject.login(token); } catch (AuthenticationException e) { //验证错误 return false; } return subject.isAuthenticated(); } }
实现效果
当输入的账户与shiro.ini配置文件里账户匹配时,登录成功,然后验证角色所拥有的权限~