【Shiro】一步步的看Shiro (一)

  • 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架构和他所支持的配置相关的内容了
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容