美文网首页
【Shiro】一步步的看Shiro (一)

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

作者: 程序员佩奇 | 来源:发表于2021-07-06 15:47 被阅读0次
  • 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架构和他所支持的配置相关的内容了

相关文章

网友评论

      本文标题:【Shiro】一步步的看Shiro (一)

      本文链接:https://www.haomeiwen.com/subject/hlorzktx.html