official shiro(Reference Manual)

时间:2023-03-08 17:17:12

Apache Shiro Reference Documentation

  1. Overview
  2. Core
  3. Spring-based Applications

1.Overview

  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</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>2.0.2</version>
    <configuration>
    <source>1.8</source>
    <target>1.8</target>
    <encoding>${project.build.sourceEncoding}</encoding>
    </configuration>
    </plugin> <!-- This plugin is only to test run our little application. It is not
    needed in most Shiro-enabled applications: -->
    <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.3.2</version>
    </dependency>
    <!-- Shiro uses SLF4J for logging. We'll use the 'simple' binding
    in this example app. -->
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.6.1</version>
    <scope>test</scope>
    </dependency>
    </dependencies> </project>
  2. src\main\resources\shiro.ini
    # =============================================================================
    # Tutorial INI configuration
    #
    # Usernames/passwords are based on the classic Mel *s' film "Spaceballs" :)
    # ============================================================================= # -----------------------------------------------------------------------------
    # Users and their (optional) assigned roles
    # username = password, role1, role2, ..., roleN
    # -----------------------------------------------------------------------------
    [users]
    root = secret, admin
    agror = agror, goodguy, schwartz
    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
  3. 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"); //1.
    Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //2.
    SecurityManager securityManager = factory.getInstance(); //3.
    SecurityUtils.setSecurityManager(securityManager); //4.
    Subject currentUser = SecurityUtils.getSubject();
    //Session session = currentUser.getSession();
    //session.setAttribute( "someKey", "aValue" );
    //session.setAttribute( "argor", "argor" ); //5.
    // Login
    if ( !currentUser.isAuthenticated() ) {
    //collect user principals and credentials in a gui specific manner
    //such as username/password html form, X509 certificate, OpenID, etc.
    //We'll use the username/password example here since it is the most common.
    //UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
    UsernamePasswordToken token = new UsernamePasswordToken("agror", "agror"); //this is all you have to do to support 'remember me' (no config - built in!):
    token.setRememberMe(true); try {
    currentUser.login( token );
    //if no exception, that's it, we're done! //print their identifying principal (in this case, a username):
    log.info( "User [" + currentUser.getPrincipal() + "] logged in successfully." ); //6.
    TestAuthorization( currentUser );
    } 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?
    } catch ( AuthenticationException ae ) {
    //unexpected condition - error?
    } finally {
    log.info( "User login status: [- " + currentUser.isAuthenticated() + " -]." ); // Logout
    currentUser.logout();
    //removes all identifying information and invalidates their session too.
    }
    } System.exit(0);
    } private static void TestAuthorization ( Subject currentUser ) {
    //6.
    // We can also test to see if they have specific role or not:
    if ( currentUser.hasRole( "schwartz" ) ) {
    log.info( currentUser.getPrincipal() + " May the Schwartz be with you!" );
    } else {
    log.info( currentUser.getPrincipal() + " , mere mortal, has't schwartz." );
    } if ( currentUser.hasRole( "goodguy" ) ) {
    log.info( currentUser.getPrincipal() + " May the goodguy be with you!" );
    } else {
    log.info( currentUser.getPrincipal() + " , mere mortal, has't goodguy." );
    } if ( currentUser.hasRole( "admin" ) ) {
    log.info( currentUser.getPrincipal() + " May the admin be with you!" );
    } else {
    log.info( currentUser.getPrincipal() + " , mere mortal, has't admin." );
    } // We can also see if they have a permission to act on a certain type of entity:
    if ( currentUser.isPermitted( "lightsaber:weild" ) ) {
    log.info("You may use a lightsaber ring.");
    } else {
    log.info("Sorry, lightsaber rings are for schwartz masters only.");
    }
    // Also, we can perform an extremely powerful instance-level permission
    // check - the ability to see if the user has the ability to access a
    // specific instance of a type:
    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!");
    }
    }
    }
  4. run
    E:\Users\Administrator\Desktop\shiro\shiro-tutorial>mvn compile exec:java
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building First Apache Shiro Application 1.0.0
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ shiro-tutorial ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] Copying 1 resource
    [INFO]
    [INFO] --- maven-compiler-plugin:2.0.2:compile (default-compile) @ shiro-tutorial ---
    [INFO] Compiling 1 source file to E:\Users\Administrator\Desktop\shiro\shiro-tutorial\target\classes
    [INFO]
    [INFO] >>> exec-maven-plugin:1.1:java (default-cli) > validate @ shiro-tutorial >>>
    [INFO]
    [INFO] <<< exec-maven-plugin:1.1:java (default-cli) < validate @ shiro-tutorial <<<
    [INFO]
    [INFO] --- exec-maven-plugin:1.1:java (default-cli) @ shiro-tutorial ---
    0 [Tutorial.main()] INFO Tutorial - My First Apache Shiro Application
    47 [Tutorial.main()] INFO Tutorial - User login status: [- false -]. E:\Users\Administrator\Desktop\shiro\shiro-tutorial>mvn compile exec:java
    [INFO] Scanning for projects...
    [INFO]
    [INFO] ------------------------------------------------------------------------
    [INFO] Building First Apache Shiro Application 1.0.0
    [INFO] ------------------------------------------------------------------------
    [INFO]
    [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ shiro-tutorial ---
    [INFO] Using 'UTF-8' encoding to copy filtered resources.
    [INFO] Copying 1 resource
    [INFO]
    [INFO] --- maven-compiler-plugin:2.0.2:compile (default-compile) @ shiro-tutorial ---
    [INFO] Compiling 1 source file to E:\Users\Administrator\Desktop\shiro\shiro-tutorial\target\classes
    [INFO]
    [INFO] >>> exec-maven-plugin:1.1:java (default-cli) > validate @ shiro-tutorial >>>
    [INFO]
    [INFO] <<< exec-maven-plugin:1.1:java (default-cli) < validate @ shiro-tutorial <<<
    [INFO]
    [INFO] --- exec-maven-plugin:1.1:java (default-cli) @ shiro-tutorial ---
    0 [Tutorial.main()] INFO Tutorial - My First Apache Shiro Application
    31 [Tutorial.main()] INFO org.apache.shiro.session.mgt.AbstractValidatingSessionManager - Enabling session validation scheduler...
    109 [Tutorial.main()] INFO Tutorial - User [agror] logged in successfully.
    109 [Tutorial.main()] INFO Tutorial - agror May the Schwartz be with you!
    109 [Tutorial.main()] INFO Tutorial - agror May the goodguy be with you!
    109 [Tutorial.main()] INFO Tutorial - agror , mere mortal, has't admin.
    109 [Tutorial.main()] INFO Tutorial - You may use a lightsaber ring.
    109 [Tutorial.main()] INFO Tutorial - You are permitted to 'drive' the 'winnebago' with license plate (id) 'eagle5'. Here are the keys - have fun!
    109 [Tutorial.main()] INFO Tutorial - User login status: [- true -].

    第一次执行时,使用一个错误的密码;第二次执行使用正确的密码;

2.Core

  1. Authentication
    1. Authenticating Subjects
      Step 1: Collect the Subject’s principals and credentials
      //Example using most common scenario of username/password pair:
      UsernamePasswordToken token = new UsernamePasswordToken(username, password); //"Remember Me" built-in:
      token.setRememberMe(true);

      Step 2: Submit the principals and credentials

      Subject currentUser = SecurityUtils.getSubject();
      currentUser.login(token);

      Step 3: Handling Success or Failure

      try {
      currentUser.login(token);
      } catch ( UnknownAccountException uae ) { ...
      } catch ( IncorrectCredentialsException ice ) { ...
      } catch ( LockedAccountException lae ) { ...
      } catch ( ExcessiveAttemptsException eae ) { ...
      } ... catch your own ...
      } catch ( AuthenticationException ae ) {
      //unexpected error?
      }

      <Login Failure Tip> The security best practice is to only show a generic failure message , for example, "Incorrect username or password".

    2. Logging Out
      currentUser.logout(); //removes all identifying information and invalidates their session too.
  2. Authorization
    1. Understanding Permissions in Apache Shiro
      Wildcard Permissions & Checking Permissions
      Simple Usage
      subject.isPermitted("sshdStart")
      subject.isPermitted("sshdStop")
      subject.isPermitted("sshdRestart") Multiple Parts
      subject.isPermitted("sshd:start")
      subject.isPermitted("sshd:stop")
      subject.isPermitted("sshd:restart") Multiple Values
      subject.isPermitted("sshd:start,stop,restart")
      subject.isPermitted("sshd:*") Instance-Level Access Control
      subject.isPermitted("sshd:start:root")
      subject.isPermitted("sshd:*:root")
      subject.isPermitted("sshd:*:*") Missing Parts
      subject.isPermitted("sshd:start:")//is equivalent to below
      subject.isPermitted("sshd:start:*")
      subject.isPermitted("sshd")//is equivalent to below
      subject.isPermitted("sshd:*:*")
    2. Elements of Authorization
      ♠Permission statements reflect behavior (actions associated with resource types) only.
      ♠A Role is a named entity that typically represents a set of behaviors or responsibilities.
      ♠A user essentially is the ‘who’ of an application. As we’ve covered previously however, the Subject is really Shiro’s ‘User’ concept.
    3. Authorizing Subjects
      • ♠Programmatically
        Role-Based Authorization
        Subject currentUser = SecurityUtils.getSubject();
        
        if (currentUser.hasRole("administrator")) {
        //show the admin button
        } else {
        //don't show the button? Grey it out?
        }

        Permission-Based Authorization

        Permission printPermission = new PrinterPermission("laserjet4400n", "print");
        
        Subject currentUser = SecurityUtils.getSubject();
        
        if (currentUser.isPermitted(printPermission)) {
        //show the Print button
        } else {
        //don't show the button? Grey it out?
        }
        Subject currentUser = SecurityUtils.getSubject();
        
        if (currentUser.isPermitted("printer:print:laserjet4400n")) {
        //show the Print button
        } else {
        //don't show the button? Grey it out?
        }
        Subject currentUser = SecurityUtils.getSubject();
        
        Permission p = new WildcardPermission("printer:print:laserjet4400n");
        
        if (currentUser.isPermitted(p) {
        //show the Print button
        } else {
        //don't show the button? Grey it out?
        }
      • ♠JDK annotations( <need> to enable AOP support in your application)
        The RequiresAuthentication annotation
        @RequiresAuthentication
        public void updateAccount(Account userAccount) {
        //this method will only be invoked by a
        //Subject that is guaranteed authenticated
        ...
        }
        //This is mostly equivalent to the following Subject-based logic: public void updateAccount(Account userAccount) {
        if (!SecurityUtils.getSubject().isAuthenticated()) {
        throw new AuthorizationException(...);
        } //Subject is guaranteed authenticated here
        ...
        }

        The RequiresGuest annotation

        @RequiresGuest
        public void signUp(User newUser) {
        //this method will only be invoked by a
        //Subject that is unknown/anonymous
        ...
        }
        //This is mostly equivalent to the following Subject-based logic: public void signUp(User newUser) {
        Subject currentUser = SecurityUtils.getSubject();
        PrincipalCollection principals = currentUser.getPrincipals();
        if (principals != null && !principals.isEmpty()) {
        //known identity - not a guest:
        throw new AuthorizationException(...);
        } //Subject is guaranteed to be a 'guest' here
        ...
        }

        The RequiresPermissions annotation

        @RequiresPermissions("account:create")
        public void createAccount(Account account) {
        //this method will only be invoked by a Subject
        //that is permitted to create an account
        ...
        }
        //This is mostly equivalent to the following Subject-based logic: public void createAccount(Account account) {
        Subject currentUser = SecurityUtils.getSubject();
        if (!subject.isPermitted("account:create")) {
        throw new AuthorizationException(...);
        } //Subject is guaranteed to be permitted here
        ...
        }

        The RequiresRoles permission

        @RequiresRoles("administrator")
        public void deleteUser(User user) {
        //this method will only be invoked by an administrator
        ...
        }
        //This is mostly equivalent to the following Subject-based logic: public void deleteUser(User user) {
        Subject currentUser = SecurityUtils.getSubject();
        if (!subject.hasRole("administrator")) {
        throw new AuthorizationException(...);
        } //Subject is guaranteed to be an 'administrator' here
        ...
        }

        The RequiresUser annotation

        @RequiresUser
        public void updateAccount(Account account) {
        //this method will only be invoked by a 'user'
        //i.e. a Subject with a known identity
        ...
        }
        This is mostly equivalent to the following Subject-based logic: public void updateAccount(Account account) {
        Subject currentUser = SecurityUtils.getSubject();
        PrincipalCollection principals = currentUser.getPrincipals();
        if (principals == null || principals.isEmpty()) {
        //no identity - they're anonymous, not allowed:
        throw new AuthorizationException(...);
        } //Subject is guaranteed to have a known identity here
        ...
        }

3.Integrating into Spring-based Applications

Shiro applications need an application singleton SecurityManager instance.

  1. web.xml
    Here is how to configure Shiro in a Spring-based web application:
    <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
    <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
    <param-name>targetFilterLifecycle</param-name>
    <param-value>true</param-value>
    </init-param>
    </filter> ... <!-- Make sure any request you want accessible to Shiro is filtered. /* catches all -->
    <!-- requests. Usually this filter mapping is defined first (before all others) to -->
    <!-- ensure that Shiro works in subsequent filters in the filter chain: -->
    <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
  2. applicationContext.xml
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <!-- override these for application-specific URLs if you like:
    <property name="loginUrl" value="/login.jsp"/>
    <property name="successUrl" value="/home.jsp"/>
    <property name="unauthorizedUrl" value="/unauthorized.jsp"/> -->
    <!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean -->
    <!-- defined will be automatically acquired and available via its beanName in chain -->
    <!-- definitions, but you can perform instance overrides or name aliases here if you like: -->
    <!-- <property name="filters">
    <util:map>
    <entry key="anAlias" value-ref="someFilter"/>
    </util:map>
    </property> -->
    <property name="filterChainDefinitions">
    <value>
    # some example chain definitions:
    /admin/** = authc, roles[admin]
    /docs/** = authc, perms[document:read]
    /** = authc
    # more URL-to-FilterChain definitions here
    </value>
    </property>
    </bean> <!-- Define any javax.servlet.Filter beans you want anywhere in this application context. -->
    <!-- They will automatically be acquired by the 'shiroFilter' bean above and made available -->
    <!-- to the 'filterChainDefinitions' property. Or you can manually/explicitly add them -->
    <!-- to the shiroFilter's 'filters' Map if desired. See its JavaDoc for more details. -->
    <bean id="someFilter" class="..."/>
    <bean id="anotherFilter" class="..."> ... </bean>
    ... <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <!-- Single realm app. If you have multiple realms, use the 'realms' property instead. -->
    <property name="realm" ref="myRealm"/>
    <!-- By default the servlet container sessions will be used. Uncomment this line
    to use shiro's native sessions (see the JavaDoc for more): -->
    <!-- <property name="sessionMode" value="native"/> -->
    </bean>
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- Define the Shiro Realm implementation you want to use to connect to your back-end -->
    <!-- security datasource: -->
    <bean id="myRealm" class="...">
    ...
    </bean>
  3. Enabling Shiro Annotations
    Here is how to enable these annotations. Just add these two bean definitions to applicationContext.xml:
    <!-- Enable Shiro Annotations for Spring-configured beans.  Only run after -->
    <!-- the lifecycleBeanProcessor has run: -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager"/>
    </bean>

.