【WEEK13】 【DAY1】Shiro Part 1【English Version】

2024.5.20 Monday

15. Shiro

15.1. Introduction to Shiro

15.1.1. What is Shiro

  • Apache Shiro is a security (permission) framework for Java.
  • Shiro makes it very easy to develop good enough applications, it can be used not only in JavaSE environment but also in JavaEE environment.
  • Shiro can accomplish: authentication, authorization, encryption, session management, web integration, caching, etc.
  • Download links:

15.1.2. What Functions Does Shiro Have

Image

  • Authentication: Identity authentication/login, verifying if a user has the corresponding identity.
  • Authorization: Permission verification, verifying if an authenticated user has certain permissions; determining what operations a user can perform, such as verifying if a user has a certain role, or fine-grained verification of whether a user has certain permissions for a resource.
  • Session Management: Managing sessions, a session is established after a user logs in, and all information of the user is stored in the session until they log out; sessions can be in a regular JavaSE environment or a web environment.
  • Cryptography: Encryption, protecting data security, such as encrypting passwords before storing them in the database instead of storing them in plain text.
  • Web Support: Easy integration into web environments.
  • Caching: Cache, for example, after a user logs in, their user information and roles/permissions do not need to be queried every time, which improves efficiency.
  • Concurrency: Shiro supports concurrent verification in multi-threaded applications, meaning permissions can automatically propagate to another thread if a new thread is started in one thread.
  • Testing: Provides testing support.
  • “Run As”: Allows a user to impersonate another user’s identity for access (if permitted).
  • Remember Me: This is a very common feature, meaning after logging in once, the user does not need to log in again next time.

15.1.3. Shiro Architecture (External)

From an external perspective, observing how Shiro works from the perspective of the application.
Image

  • Subject: The object directly interacting with the application code is the Subject, meaning the core of Shiro’s external API is the Subject. The Subject represents the current “user”, which doesn’t necessarily have to be a specific person; anything interacting with the current application is a Subject, such as web crawlers, robots, etc.; all interactions with the Subject are delegated to the SecurityManager; the Subject is essentially a facade, and the SecurityManager is the actual executor.
  • SecurityManager: Security manager; all security-related operations interact with the SecurityManager; it manages all Subjects; it can be seen as the core of Shiro, responsible for interacting with other components of Shiro, similar to the role of DispatcherServlet in SpringMVC.
  • Realm: Shiro obtains security data (such as users, roles, permissions) from the Realm, meaning if the SecurityManager needs to verify a user’s identity, it needs to obtain the corresponding user from the Realm for comparison to determine if the user’s identity is legitimate; it also needs to get the user’s corresponding roles/permissions from the Realm to verify if the user can perform certain operations; the Realm can be seen as a DataSource.

15.1.4. Shiro Architecture (Internal)

Image

  • Subject: Any “user” that can interact with the application.
  • SecurityManager: Equivalent to DispatcherServlet in SpringMVC; it is the heart of Shiro; all specific interactions are controlled through the SecurityManager; it manages all Subjects and is responsible for authentication, authorization, session, and cache management.
  • Authenticator: Responsible for Subject authentication, it is an extension point that can be custom implemented; it can use authentication strategies (Authentication Strategy), determining when user authentication passes.
  • Authorizer: Authorizer, that is, access controller, used to determine whether the subject has permission to perform corresponding operations; controlling which functionalities a user can access in the application.
  • Realm: There can be one or more Realms, which can be considered as security entity data sources, used to obtain security entities; it can be JDBC implementation, memory implementation, etc.; provided by users; so generally, applications need to implement their own Realm.
  • SessionManager: Component managing session lifecycles; Shiro can be used not only in web environments but also in regular JavaSE environments.
    CacheManager: Cache controller, managing caches such as user, role, permission, etc.; because these data rarely change, putting them in caches can improve access performance.
  • Cryptography: Password module, Shiro provides some common encryption components for tasks like password encryption/decryption.

15.2. Hello World

15.2.1. Create a New springboot-08-shiro Project

Image

15.2.2. Create a Module Named hello-shiro

Image

15.2.2.1. Modify springboot-08-shiro\hello-shiro\pom.xml

在这里插入图片描述
Essentially, you add the appropriate version-numbered dependencies against quickstart (go to
https://mvnrepository.com/ to download the appropriate version)

<?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">
    <parent>
        <artifactId>springboot-08-shiro</artifactId>
        <groupId>org.P38</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hello-shiro</artifactId>

    <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>
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>2.0.0</version>
        </dependency>

        <!-- configure logging -->
        <!-- https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>2.0.7</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j2-impl</artifactId>
            <version>2.20.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.20.0</version>
        </dependency>

    </dependencies>

</project>
15.2.2.2. Copy log4j2.xml, shiro.ini, and Quickstart.java from the quickstart to similar locations in this project.

在这里插入图片描述

15.2.2.3. Run Quickstart.java

An error occurred: Class file has wrong version 55.0, should be 52.0. Please delete the file or ensure it is located in the correct classpath subdirectory. Modifying the perspective of usage versions also doesn’t help. After consulting the official documentation, it appears that a version of 11+ is required. Thus, this version is not feasible. Returning to GitHub to download a lower version for learning purposes.

15.2.3. Using version 1.4.x

在这里插入图片描述

15.2.3.1. Modify pom.xml again
<?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">
    <parent>
        <artifactId>springboot-08-shiro</artifactId>
        <groupId>org.P38</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>hello-shiro</artifactId>

    <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>
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!-- configure logging -->
        <!-- https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.21</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>

</project>
15.2.3.2. Recopy log4j.properties, shiro.ini, and Quickstart.java from the quickstart to similar locations in this project.

在这里插入图片描述

15.2.3.3. Run Quickstart.java

Logs are printed successfully.
在这里插入图片描述
Study and comment the file:

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

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;

/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {

        // The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:

        // Use the shiro.ini file at the root of the classpath:
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

        // For this simple example quickstart, make the SecurityManager
        // accessible as a JVM singleton. Most applications wouldn't do this
        // and instead rely on their container configuration or web.xml for
        // webapps. That is outside the scope of this simple quickstart, so
        // we'll just do the bare minimum so you can continue to get a feel
        // for things.
        SecurityUtils.setSecurityManager(securityManager);

        // Now that a simple Shiro environment is set up, let's see what you can do:

        // get the currently executing user:
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        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 + "]");
        }

        // Let's login the current user so we can check against roles and permissions:
        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 (AuthenticationException ae) {
                // unexpected condition? error?
            }
        }

        // Say who they are:
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        // Test a role:
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }

        // Test a typed permission (not instance-level):
        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.");
        }

        // A (very powerful) Instance Level permission:
        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!");
        }

        // Log out:
        currentUser.logout();

        // Exit
        System.exit(0);
    }
}
  • The corresponding functionality exists in Spring Security (just with different names):
  // Get the currently executing user object (Subject)
  Subject currentUser = SecurityUtils.getSubject();
  Session session = currentUser.getSession();
  currentUser.isAuthenticated()
  currentUser.getPrincipal()
  currentUser.hasRole("schwartz")
  currentUser.isPermitted("lightsaber:wield")
  currentUser.logout();
  • 32
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值