一步步看Shiro(1)

  • 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)![](https://img.soogif.com/IhBHYjkYnJ9NtV2ZrAc4i1G5vYoBo4XU.gif?imageMogr2/thumbnail/!51.79834606517432p&scope=mdnice)

    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架构和他所支持的配置相关的内容了

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享