您的第一个 Apache Shiro 应用程序
引入依赖:
<?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/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.tianfan</groupId><artifactId>shiroTest</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>1.12.0</version></dependency><!-- Shiro uses SLF4J for logging. We'll use the 'simple' bindingin this example app. See https://www.slf4j.org for more info. --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.21</version><scope>compile</scope></dependency><dependency><groupId>org.slf4j</groupId><artifactId>jcl-over-slf4j</artifactId><version>1.7.21</version><scope>test</scope></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency></dependencies></project>
lombok.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="30 seconds"><!-- 彩色日志依赖 --><conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" /><conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" /><conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" /><!-- 日志文件储存地址, 通过application配置文件传入 --><!-- <springProperty scope="context" name="LOG_PATH" source="logback.logDir" />--><!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--><property name="LOG_PATH" value="./logs"/><!-- 控制台彩色日志格式 --><property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" /><!-- 日志文件日志格式 --><property name="FILE_LOG_PATTERN" value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%15t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" /><!-- 控制台输出 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${CONSOLE_LOG_PATTERN}</pattern><charset>UTF-8</charset></encoder><filter class="ch.qos.logback.classic.filter.LevelFilter"><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter></appender><!-- 按照每天及大小生成日志文件 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--日志文件输出的文件名--><FileNamePattern>${LOG_PATH}/my-blog-site.%d{yyyy-MM-dd}.%i.log</FileNamePattern><!--日志文件最大大小--><maxFileSize>100MB</maxFileSize><!--日志文件保留天数--><maxHistory>30</maxHistory></rollingPolicy><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><pattern>${FILE_LOG_PATTERN}</pattern><charset>UTF-8</charset></encoder><!-- 过滤级别,如果想分类生成日志文件的话(分成debug、info、error等三个日志文件, 每个文件只记录自己级别的日志),1. 直接把这个 <appender> 复制三分改一下 FileNamePattern 和 name.2. 把 <filter> 注释去掉改一下 level 就可以了--><!-- <filter class="ch.qos.logback.classic.filter.LevelFilter">--><!-- <level>info</level>--><!-- <onMatch>ACCEPT</onMatch>--><!-- <onMismatch>DENY</onMismatch>--><!-- </filter>--></appender><!-- 日志输出级别如果使用springProfile, 就需要在application配置文件中通过 spring.profiles.active=dev 来指定环境,也可以直接去掉 <springProfile> 这个标签或者把它整个注释掉--><springProfile name="dev,prod"><logger name="org.springframework" level="INFO" additivity="false"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/></logger><logger name="com.netflix" level="INFO" additivity="false"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/></logger><logger name="com.pro.test" level="DEBUG" additivity="false"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/></logger><logger name="java.sql" level="DEBUG" additivity="false"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/></logger><!--项目包的路径--><logger name="com.pro" level="DEBUG,INFO" additivity="false"><appender-ref ref="CONSOLE"/><appender-ref ref="FILE"/></logger></springProfile><root level="INFO"><appender-ref ref="CONSOLE" /><appender-ref ref="FILE" /></root>
</configuration>
先不涉及web的,想看web的请往后面看:
模拟数据: shiro.ini:
# =============================================================================
# Tutorial INI configuration
#
# Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)
# =============================================================================# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5
package org.tianfan;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
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.session.Session;
import org.apache.shiro.subject.Subject;
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");//1.拿到 IniSecurityManagerFactory ini的管理工具IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");//2.拿到安全管理SecurityManager securityManager = factory.getInstance();//3.配置一下SecurityUtils类,以后各种操作就靠这个类SecurityUtils.setSecurityManager(securityManager);//拿到主体,当前正在与软件交互的东西Subject currentUser = SecurityUtils.getSubject();//获得SessionSession session = currentUser.getSession();//这个不用提示了吧session.setAttribute( "someKey", "aValue" );System.exit(0);}
}
使用Shiro
这是一个特定于 Shiro 的实例,它提供了您习惯于常规 HttpSessions 的大部分功能,但有一些额外的好处和一个很大的区别:它不需要 HTTP 环境!Session
如果部署在 Web 应用程序内,则默认情况下将基于 Web 应用程序。但是,在非 Web 环境中,比如这个简单的教程应用程序,Shiro 将默认自动使用其企业会话管理。这意味着,无论部署环境如何,您都可以在任何层的应用程序中使用相同的 API!这打开了一个全新的应用程序世界,因为任何需要会话的应用程序都不需要强制使用 或 EJB 有状态会话 Bean。而且,任何客户端技术现在都可以共享会话数据。Session
HttpSession
HttpSession
所以现在你可以获得一个和他们的.那些真正有用的东西呢,比如检查他们是否被允许做一些事情,比如检查角色和权限?Subject
Session
好吧,我们只能对已知用户进行这些检查。我们上面的实例代表当前用户,但谁是当前用户?好吧,他们是匿名的 - 也就是说,直到他们至少登录一次。所以,让我们这样做:Subject
if ( !currentUser.isAuthenticated() ) {//currentUser.isAuthenticated()要是为true就是登录了,加了非,就是没有登录的就往下走//这个lonestarr和vespa是要自己输入的数据,用户名,密码之类的,从前端表格获取的,都行UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");//表示开启“记住我”功能,即在下次登录时,系统会自动填充上一次登录时的用户名和密码,方便用户快速登录系统。token.setRememberMe(true);//currentUser.login(token)是一个登录方法,它将用户的凭据与系统中存储的用户信息进行比较,如果凭据匹配,则将用户标识为已验证用户。在这个例子中,token是一个UsernamePasswordToken对象,它包含了用户的用户名和密码。如果用户的凭据被验证成功,那么用户将被标识为已验证用户,否则将抛出异常。currentUser.login(token);
}
那么如何管理这些异常呢?答案是捕获异常
try {currentUser.login( token );//if no exception, that's it, we're done!
} catch ( UnknownAccountException uae ) {//username wasn't in the system, show them an error message?
} catch ( IncorrectCredentialsException ice ) {//password didn't match, try again?
} catch ( LockedAccountException lae ) {//account for that username is locked - can't login. Show them a message?
}... more types exceptions to check if you want ...
} catch ( AuthenticationException ae ) {//unexpected condition - error?
}
好了,现在让我们搞一个完整的项目:
完整代码:
package org.tianfan;
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.subject.Subject;
import org.apache.shiro.util.Factory;public class Tutorial {public static void main(String[] args) {// 读取INI配置文件并创建SecurityManagerFactory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);// 获取当前用户Subject currentUser = SecurityUtils.getSubject();// 登录if (!currentUser.isAuthenticated()) {UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");try {currentUser.login(token);System.out.println("登录成功!");} catch (UnknownAccountException uae) {System.out.println("未知账户!");} catch (IncorrectCredentialsException ice) {System.out.println("密码不正确!");} catch (LockedAccountException lae) {System.out.println("账户已锁定!");} catch (AuthenticationException ae) {System.out.println("认证失败!");}}// 检查用户是否拥有某个角色if (currentUser.hasRole("goodguy")) {System.out.println("您拥有goodguy角色!");} else {System.out.println("您没有goodguy角色!");}// 检查用户是否拥有某个权限if (currentUser.isPermitted("winnebago:drive:eagle5")) {System.out.println("您拥有winnebago:drive:eagle5权限!");} else {System.out.println("您没有winnebago:drive:eagle5权限!");}// 登出currentUser.logout();}
}
数据文件:
# =============================================================================
# Tutorial INI configuration
#
# Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)
# =============================================================================# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5
运行结果:
Shiro与SpringbootWeb的正式结合使用:
感觉字数太多了,下一章再讲吧