Don't you know shiro after reading this, small example (with source code)

Don't you know shiro after reading this, small example (with source code)

Preface

Today is learning Shiro's notes. All the learning notes are suitable for beginners. If you have studied Shiro as a review, I will often take them back. It is so quick and convenient to review a lot of things by myself. That's not a compliment to see here? After all, a lot of learning and taking notes take several days, so bloggers update fast or slow, I hope this blog will help you;

Let's finally learn a small application of Shiro from a small example, since only writing code can better understand it, the source code is at the end;

introduce

Official website: https://shiro.apache.org/

From Baidu Encyclopedia:

Quickstart

First we go to the official website, then there is a download here, we click Download;

Here's the latest version updated to 1.9.1, click and go down, let's go to github to download, we use this link to get into github

Let's click code to download a zip compressed file

There's a Quickstart Quick Start in the open file. Refer to this code and let's see

There are a lot of English comments in this, I believe you can understand it at a glance, and it is very simple or incorrect. You can experience the code in 10 minutes. I don't really understand staying here for translation.

/*
 * 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.ini.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.lang.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
        // (file: and url: prefixes load from files and urls respectively):
        // First we can read the ini file and create a factory instance
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        // Then we can instance an object from the factory called securityManager
        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.
        // We can give this instance object to the tool class SecurityUtils, and it will help us do some steps
        SecurityUtils.setSecurityManager(securityManager);

        // Now that a simple Shiro environment is set up, let's see what you can do:
        // In fact, we found that the first few steps, we wrote so much code, are they all fixed, like we used jdbc to create links to close links
        // Then we get the first object we can think of as a user, and the first one comes.
        // We remember this object
        // get the currently executing user:
        Subject currentUser = SecurityUtils.getSubject();

        // We can also create a session on this object, where sessions are not sessions within http, but they do understand each other
        // Do some stuff with a Session (no need for a web or EJB container!!!)
        Session session = currentUser.getSession();

        // Can be used to store and take values
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("Retrieved the correct value! [" + value + "]");
        }

        // Shiro security management, see Authenticated must know authorization, see if there is permission
        // let's login the current user so we can check against roles and permissions:
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            // Look at the words, remember my function
            token.setRememberMe(true);
            try {
                // Sign in. What did he fail to sign in on, exceptional
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                // No user threw this exception UnknownAccountException
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                // Password error
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                // No privileges
                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) {
                // Guess what this is
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):,
        // After successful login, we can get the user information (here is the user name)
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

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

        // You can also see if you have access to the resource
        //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
        //all done - log out!
        currentUser.logout();

        // Program End
        System.exit(0);
    }
}

Let's take a closer look at this diagram here. The first subject can be understood as a user, managed through the security manager, and finally allowed you to access the data. This is a small example given officially. Quick Start, if you don't understand it, let's take a look at the following small example.

A small example

Let's start with a small example of springsecurity. Here we take it and use it. Here's the same tutorial that springsecurity does:

Don't you springsecurity after reading this? Small instance of springsecurity, simple implementation of site login authorization (with source code)

Similarly, let's look at the effect first. Here we mainly complete the page. The page is simple and easy to understand, just to achieve the function.

The first step is to enter the home page, where only the public information is displayed.

Then log in, we have three users here, and then implement different users to show no user interface, at a glance you can see that

For example, we log in to root user

Log in to zhangsan

lisi needn't say anything, this is simple functionality implemented through Shrio, let's look at the code:

To create a new project, first import dependencies

<dependencies>


    <!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
    <dependency>
        <groupId>com.github.theborakompanioni</groupId>
        <artifactId>thymeleaf-extras-shiro</artifactId>
        <version>2.1.0</version>
    </dependency>



    <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring-boot-web-starter -->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring-boot-web-starter</artifactId>
        <version>1.9.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>


    <!-- mysql-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>


    <!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>


    <!--Template Engine Dependency:mybatis-plus Report exceptions when code is generated-->
    <dependency>
        <groupId>org.apache.velocity</groupId>
        <artifactId>velocity-engine-core</artifactId>
        <version>2.0</version>
    </dependency>
    <!--To configure ApiModel Not valid in entity class-->
    <dependency>
        <groupId>com.spring4all</groupId>
        <artifactId>spring-boot-starter-swagger</artifactId>
        <version>1.5.1.RELEASE</version>
    </dependency>
    <!--freemarker-->
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.30</version>
    </dependency>
    <!--beetl-->
    <dependency>
        <groupId>com.ibeetl</groupId>
        <artifactId>beetl</artifactId>
        <version>3.3.2.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.80</version>
    </dependency>

</dependencies>

Let's look at the project structure first:

First of all, what do we need to register this in the spring container? First, we'll look at the config configuration. First, we'll look at the three objects in our diagram. Then we'll create a dependency relationship between them. From top to bottom, fixed. That's the same line of code that we just used in quickstart. Here's all the administrative privileges.

@Configuration
public class ShiroConfig {

    //Create realm objects
    @Bean
    public UserRealm userRealm() {
        UserRealm realm = new UserRealm();
        /*        //Set encryption algorithm to md5
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5");
        //Set Encryption Number
        credentialsMatcher.setHashIterations(1024);
        realm.setCredentialsMatcher(credentialsMatcher);*/
        return realm;
    }

    //DefaultWebSecurityManager Manager
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    // Set Permission Filter
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(
        @Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);


        /*
            anon: Anyone can access
            authc: Authentication is required to access
            user: Use the Remember Me feature before you can use it
            perms[]: A resource can only be accessed if it has a corresponding permission
            role: Role has permissions to access
         */
        // Store custom filter s
        LinkedHashMap<String, Filter> filtersMap = new LinkedHashMap<>();
        filtersMap.put("permsOrFilter", new RoleFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);

        Map<String, String> filter = new LinkedHashMap<>();
        //Set Logon Exit
        filter.put("/logout", "logout");

        // Then what perms do you have? Only a single privilege, single authentication, can be achieved here.
        // Can't reach the ssvip we want or access the vip service
        // So here we rewrite the filter, and then we can do that

        /* filter.put("/user/ssvip", "perms[ssvip]");
        //You can also access vip services if you want ssvip
        filter.put("/user/svip", "perms[svip]");
        filter.put("/user/vip", "perms[vip]");*/

        //        Custom or Role Authentication
        filter.put("/user/ssvip", "permsOrFilter[ssvip]");
        filter.put("/user/svip", "permsOrFilter[ssvip,svip]");
        filter.put("/user/vip", "permsOrFilter[ssvip,svip,vip]");
        //Must be authorized to
        filter.put("/user/*", "authc");



        shiroFilterFactoryBean.setFilterChainDefinitionMap(filter);
        //Not logged in to the login page
        shiroFilterFactoryBean.setLoginUrl("/tologin");
        //Unauthorized Jump to Unauthorized Page
        //        shiroFilterFactoryBean.setUnauthorizedUrl("");

        return shiroFilterFactoryBean;
    }

    //shiro integration thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

}

Here is the UserRealm we created. User information is first authenticated, then authorized. That is, we login through the shrio framework, first enter the parameters that AuthenticationInfo obtains through the front-end, go to the database to find, the authentication can successfully put the object information into Session, where Session is not httpSession

Then go to AuthorizingRealm to get the user rights to log in;

public class UserRealm extends AuthorizingRealm {
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //To grant authorization
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        info.addStringPermission("ROLE_vip");
        //You can get the following user object
        Subject subject = SecurityUtils.getSubject();
        Users user = (Users) subject.getPrincipal();

        //Add permissions for the current user
        info.addStringPermission(user.getUserRole());

        return info;
    }

    @Autowired
    UsersService usersService;



    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //Authentication
        /*String name ="root";
        String password = "root";*/

        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
        QueryWrapper<Users> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_name",usernamePasswordToken.getUsername());
        Users user = usersService.getOne(queryWrapper);


        if (!usernamePasswordToken.getUsername().equals(user.getUserName())) {
            return null; //Automatically throw username error exception, password shiro will do it yourself
        }

        //We can save the logged in object into session, where session is not httpSession
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("user",user);

        return new SimpleAuthenticationInfo(user, user.getUserPassword(), user.getUserName());
    }
}

Because we want to complete a multi-privilege authentication, or OR authentication, there is no such authentication by default, so we have written a filter to assign privileges to user roles by priority, that is, your ssvip can access svip and vip. Configuration is all right. In fact, it is very simple to do debug yourself how to change. Here, of course, the roles used can also do Permission and so on.

@Component
public class  RoleFilter extends RolesAuthorizationFilter {
    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
            throws IOException {

        final Subject subject = getSubject(request, response);
        final String[] rolesArray = (String[]) mappedValue;

        if (rolesArray == null || rolesArray.length == 0) {
            // When no roles are specified, there is no need to check to allow access
            return true;
        }

        for (String roleName : rolesArray) {
            System.out.println("==================");
            System.out.println(roleName);
            //If we set role s we can use this
            System.out.println(subject.hasRole(roleName));
            System.out.println(subject.isPermitted(roleName));
            if (subject.isPermitted(roleName)) {
                return true;
            }
        }
        return false;
    }
}

We get the username user password through the front end, and then throw the error message by exception, above and below are routes;

This is the basic process, the rest are mybaitis framework code, not to be concerned here;

Then integrate thymeleaf, where there are dependencies remember to import dependencies, and config configures it, injects a bean, and the code is simple, with session s and some Shiro tags: shiro:hasAnyPermissions, you know at a glance, there's nothing to say;

If you still want to know, you can search for more, such as here, you can see at a glance: https://wenku.baidu.com/view/1b0c053dfc00bed5b9f3f90f76c66137ee064faf.html

The main thing is to try it yourself. It's easy to write thieves once. Here's the source code, which can compare with the simple functions under implementation.

Links: https://pan.baidu.com/s/1QNq66gCJMXMXW0kwlYltEQ?pwd=q41v 
Extraction Code: q41v

Summary

Finally, through this small example, I hope you can have a simple and practical Shiro Quick Start Chapter, you must do it yourself. Otherwise, just look at how it can be done, and follow up with the small features, you can see that there is no point in praise of the blogger, leave a focus on it, there are more wonderful content, bye~

First of all, I would like to introduce myself. Xiaobian graduated from Master Jiaotong University in 13 years, once stayed in a small company, went to factories such as Huawei OPPO, and entered Ali in 18 years until now. Knowing that most junior and intermediate Java engineers often need to grope for growth or sign up for classes to improve their skills, but the tuition fees of nearly 10,000 yuan for training institutions are very stressful. Their own self-study efficiency is low and long, and they are prone to encounter ceiling technology. So I have collected a complete set of learning materials for java development for you. The original intention is very simple. I want to help friends who want to learn by themselves but don't know where to start, and at the same time reduce the burden on you. Add the business card below to get the complete set of learning materials.

Tags: Back-end Front-end Android Interview

Posted by acemods on Sun, 31 Jul 2022 02:40:21 +0930