- shiro可以应用于任何应用
- 简单的例子我们先把shiro跑起来
- 这个实例需要jdk1.6或更高版本,maven在2.2.1或更高版本
初始化一下环境
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.shiro.tutorials</groupId>
<artifactId>shiro-tutorial</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>First Apache Shiro Application</name>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<!-- 运行main函数java代码用的,如果用idea可以不考虑 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<classpathScope>test</classpathScope>
<mainClass>Tutorial</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.1</version>
</dependency>
<!-- slf4j日志包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
<scope>test</scope>
</dependency>
<!-- 桥接包来代替commons-logging把具体实现委托给slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.21</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
- 来创建个启动类,在
src/main/java/Tutorial.java
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Tutorial {
private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);
public static void main(String[] args) {
log.info("My First Apache Shiro Application");
System.exit(0);
}
}
- 执行一下main方法就好咯
上面只是搭建一个很简单的应用,下面就具体说说需要配置写什么
SecurityManager
- shiro的核心管理器,在Shiro里面几乎所有的东西和SecurityManager有关系,每一个Shiro应用中必然存在一个SecurityManager,所以我们必须干一件事情就是设置SecurityManager
Configuration
- 我们可以实例话SecurityManager,而且shiro为我们启动SecurityManager提供了很多的配置项,看一下
- 下面就先用shiro.ini为例:
src/main/resources/shiro.ini
# =============================================================================
# Tutorial INI configuration
#
# Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)
# =============================================================================
# -----------------------------------------------------------------------------
# [users] 用来配置用户以及密码角色的,后面可以通过数据库来配置,这里只是演示
# 配置方法:username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz
# -----------------------------------------------------------------------------
# roles是配置角色的
# 配置方法:roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5
- 配置好了以后我们就可以实例话SecurityManager了
public static void main(String[] args) {
log.info("My First Apache Shiro Application");
//1.IniSecurityManagerFactory通过工厂模式的方法读取classpath路径下的shiro.ini文件,得到一个工厂,
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
//2.通过工厂获取到SecurityManager的实例对象
SecurityManager securityManager = factory.getInstance();
//3.这里是设置到SecurityUtils的静态单利当中,JVM可以直接访问,如果说使用spring或者其他复杂的应用,会通过框架的方式放在特定的内存中进行维护(例如在Web应用程序的ServletContext或Spring)
SecurityUtils.setSecurityManager(securityManager);
System.exit(0);
}
Subject
- 在上面实例中,我们可能需要直到谁是用户?用什么表示当前用户?,当前用户是否允许执行某某操作?,所以会出现Subject的概念
- 为什么要用Subject呢?而不用User?官方中说的意思是User代表的是人类,但是在应用程序中,Subject可以看作一个人,也可以是第三方进程,守护进程账户类似的东西进行形容
Subject currentUser = SecurityUtils.getSubject();
//我们可以通过SecurityUtils.getSubject()的方式获取当前用户,当用户还没有登陆的时候则是微登陆状态匿名的,官方解释;当前执行用户的安全特定视图,它基于与当前线程或传入请求相关联的用户数据获取对象。
那么我们有了上面的用户主题,可以用来做些什么呢?看下面。
session
- session是shiro维护的一个特殊的实例,可以把他看作HttpSession,shiro的session会额外增加一些好东西,更重要的特点是可以不依赖于http环境,独立存在
- 在web环境下是基于httpSession的,但是在非web环境下也可以使用session
说完了Subject和session,那么我们如何去校验当前用户是否可以执行某一操作?如何检查他们的权限,角色?
首先我们需要为已知当前登陆的用户进行权限校验,我们都知道Subject代表当前的用户,但是谁?是当前的用户呢?,好吧,他们是匿名的,直到他们登陆了一次以后,我们可以获取到当前登陆的用户。
if ( !currentUser.isAuthenticated() ) {
//我们用GUI特定的方式收集principals(主体,用户) and credentials(凭据,密码)
//比如form表单提交的用户名密码,或者OpenId等
//这里使用的是用户名密码
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
//内置的,设置登陆后记住我
token.setRememberMe(true);
currentUser.login(token);
}
- 上面其实就是进行了一个登陆的操作,那么登陆遇到错误怎么办呢?
try {
currentUser.login( token );
//正常登陆
} catch ( UnknownAccountException uae ) {
//用户不存在的异常
} catch ( IncorrectCredentialsException ice ) {
//密码不匹配,是否在进行重试呢?
} catch ( LockedAccountException lae ) {
//用户被锁定了,是不是需要给告知用户被锁定呢?
}
... more types exceptions to check if you want ...
} catch ( AuthenticationException ae ) {
//意外情况
}
- 如果shiro提供的异常不满足你,也可以抛出自己自定义的异常
- 好了,我们有了一个登陆的用户以后,可以做些什么呢?
- 下面就是官方给出的一个完成例子:
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Tutorial {
private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);
public static void main(String[] args) {
log.info("My First Apache Shiro Application");
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
// 获取当前用户,在没登陆的情况下是匿名的
Subject currentUser = SecurityUtils.getSubject();
// 获取shiro的session实例
Session session = currentUser.getSession();
session.setAttribute("someKey", "aValue");
String value = (String) session.getAttribute("someKey");
if (value.equals("aValue")) {
log.info("Retrieved the correct value! [" + value + "]");
}
// 校验是否认证过了
if (!currentUser.isAuthenticated()) {
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
token.setRememberMe(true);
try {
currentUser.login(token);
} catch (UnknownAccountException uae) {
log.info("There is no user with username of " + token.getPrincipal());
} catch (IncorrectCredentialsException ice) {
log.info("Password for account " + token.getPrincipal() + " was incorrect!");
} catch (LockedAccountException lae) {
log.info("The account for username " + token.getPrincipal() + " is locked. " +
"Please contact your administrator to unlock it.");
}
// ... catch more exceptions here (maybe custom ones specific to your application?
catch (AuthenticationException ae) {
//unexpected condition? error?
}
}
//获取当前登录用户信息
log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
//校验角色
if (currentUser.hasRole("schwartz")) {
log.info("May the Schwartz be with you!");
} else {
log.info("Hello, mere mortal.");
}
//校验权限
if (currentUser.isPermitted("lightsaber:wield")) {
log.info("You may use a lightsaber ring. Use it wisely.");
} else {
log.info("Sorry, lightsaber rings are for schwartz masters only.");
}
//还可以校验具体的某个功能的权限
if (currentUser.isPermitted("winnebago:drive:eagle5")) {
log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " +
"Here are the keys - have fun!");
} else {
log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
}
//退出登陆
currentUser.logout();
System.exit(0);
}
}
总结
- 上面只是简单的初步介绍了一下shiro的使用,说了几个核心的概念,SecurityManager,session,Subject
- 如果不想使用shiro.ini配置文件怎么办呢,我们在实际开发中确实也很少使用这种方式,那么我们肯定需要和数据库打交道
- 想解决shiro.ini不想用的问题,下面就需要继续学习一下关于Shiro架构和他所支持的配置相关的内容了
网友评论