Apache Shiro
一、Shiro介绍:
Apache软件基金会专门针对系统中的登录、加密、权限认证、授权等等功能进行了封装,不仅仅适用于JavaWeb项目,CS架构的系统也可以使用Shiro。
Apache Shiro是一个强大且易用的Java安全框架,有身份验证、授权、密码学(加密)和会话管理。使用Shiro的易于理解的API,可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
相同的产品:
Spring security 重量级安全框架。
Apache Shiro 轻量级安全框架。
二、Shiro的使用
前提:创建一个普通的Maven项目。
准备(导包):配置Shiro需要的jar包
<dependencies> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
1、密码加密
注意:加密方式一般有 MD5 和 SHA 两种,下面测试使用的是MD5加密方式
MD5加密方式特点:只能加密,不能解密。(在数据库中保存的密码都是加密过后的密码,使用MD5加密方式的话,登录的密码在登录之前都要先进行加密,因此必须保证登录前的加密规则要和数据库中密码的加密规则相同(加密规则:加密方式、盐值、加密次数))
public class ShiroTest extends BaseTest { @Test public void test() throws Exception { String password = "123"; /** * String algorithmName * 加密方式: MD5 和 SHA 两种 * Object source * 要加密的内容 [一般填密码字符串] * Object salt * 盐值[一般也是填字符串] * int hashIterations * 加密次数 */ SimpleHash simpleHash = new SimpleHash("MD5", password,"wang",10); //MD5加密方式的结果:32位十六进制的数字组成的字符串 System.out.println(simpleHash); } /** * 测试:将数据库中的密码进行加密 * 为了防止记不住密码,先在数据库中执行 update employee set password = username; */ @Autowired private IEmployeeService employeeService; @Test public void testUpdateAllPassword() throws Exception { SimpleHash simpleHash = null; List<Employee> list = employeeService.findByJPQL("from Employee e"); for (Employee employee : list) { simpleHash = new SimpleHash("MD5", employee.getUsername(),"wang",10); //重新设置加密之后的密码 employee.setPassword(simpleHash.toString()); //保存数据【更新】 employeeService.save(employee); } } }
2、登录验证
2.1 准备 .ini 文件类型的数据(在ini文件中,#代表注释)
# ----------------------------------------------------------------------------- # 所有用户数据以及他属于哪些角色 # root = 123, admin, schwartz # root表示用户名 123是密码 admin是root这个用户属于哪个角色 # ----------------------------------------------------------------------------- [users] root = 123, admin guest = 123, schwartz presidentskroob = 123, president darkhelmet = 123, darklord, schwartz lonestarr = 123, goodguy, schwartz # ----------------------------------------------------------------------------- # 所有角色以及对应的权限 # admin = * admin是角色名称 *表示他拥有所有权限 # schwartz = employee:* schwartz是角色名称 employee:* 表示schwartz角色具备的权限:/employee/* # goodguy = department:save goodguy是角色名称 department:save 表示goodguy角色具备的权限:/department/save # ----------------------------------------------------------------------------- [roles] admin = * schwartz = employee:* goodguy = department:save
2.2 测试登录验证
import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.UnknownAccountException; 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.Test; public class ShiroTest { /** * 1)准备资源【数据--ini配置文件来准备】 * 2)创建SecurityManager对象 * 读取ini文件【正式项目要换成数据库查询】得到一个工厂对象 * 通过工厂创建一个SecurityManager对象 * 将SecurityManager对象放入Shiro的上下文中 * 获取当前用户 * 判断是否已经登录 isAuthenticated() * 登录【login 传入一个UsernamePasswordToken】 * 是否属于某个角色【hasRole】 * 是否拥有某些权限【isPermitted】 * 退出【logout()】 * @throws Exception */ @Test public void test() throws Exception { //读取shiro.ini文件数据,生成一个SecurityManager工厂对象 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //通过工厂创建一个SecurityManager对象 SecurityManager securityManager = factory.getInstance(); //将SecurityManager对象放入Shiro的上下文中 SecurityUtils.setSecurityManager(securityManager); //获取当前用户【不论你是否已经登录,只要你访问就认为你是一个用户】 Subject currentUser = SecurityUtils.getSubject(); System.out.println("判断用户root是否已经登录:" + currentUser.isAuthenticated()); //准备一个令牌【包含用户名和密码,模拟项目中的前端登录表单提交过来的请求参数】 UsernamePasswordToken token = new UsernamePasswordToken("root","123"); try { if(!currentUser.isAuthenticated()){ //用户登录 currentUser.login(token); } } catch (UnknownAccountException e){ //UnknownAccountException:表示用户名不存在; Unknown(未知的) Account(账户、用户名) e.printStackTrace(); System.out.println("登录失败-用户名不存在!"); } catch (IncorrectCredentialsException e){ //IncorrectCredentialsException :表示密码错误; Incorrect(不正确的) Credentials(凭证、密码) e.printStackTrace(); System.out.println("登录失败-密码错误!"); } catch (AuthenticationException e) { e.printStackTrace(); } System.out.println("判断用户root是否已经登录:" + currentUser.isAuthenticated()); //判断root用户是否属于某个角色 System.out.println("判断root用户是否属于admin角色:" + currentUser.hasRole("admin")); System.out.println("判断root用户是否属于itsource角色:" + currentUser.hasRole("itsource")); System.out.println("判断root用户是否属于guest角色:" + currentUser.hasRole("guest")); //判断root用户是否拥有某些权限 System.out.println("判断root用户是否拥有所有权限:" + currentUser.isPermitted("*")); System.out.println("判断root用户是否拥有employee:*权限:" + currentUser.isPermitted("employee:*")); //用户退出系统 currentUser.logout(); System.out.println("判断用户root是否已经登录:" + currentUser.isAuthenticated()); } }