Home  >  Article  >  Java  >  How to use the Apache Shiro security framework in Java

How to use the Apache Shiro security framework in Java

WBOY
WBOYforward
2023-04-18 19:40:101029browse

    1. Introduction to Shiro:

    Apache Shiro is a Java security (permission) framework.
    Shiro can easily develop good enough applications, which can be used not only in the JavaSE environment, but also in the JavaEE environment. Shiro can do it all, authentication, authorization, encryption, session management, web integration, caching and more.

    How to use the Apache Shiro security framework in Java

    shiro functions:

    How to use the Apache Shiro security framework in Java

    Authentication: identity authentication, login, verify whether the user has the corresponding Identity;
    Authorization: authorization, that is, permission verification, verifying whether an authenticated user has a certain permission, that is, determining whether the user can perform any operations, such as: verifying whether a user has a certain role, or fine-grained Verify whether a user has a certain permission on a certain resource!
    Session Manager: Session management, that is, the first session after the user logs in. Before exiting, all its information is in the session; the session can It is an ordinary JavaSE environment, or it can be a Web environment;
    Cryptography: Encryption to protect the security of data, such as password encryption and storage in the database instead of plain text storage; Web Support: Web support, which can be easily integrated into Web environment;
    Caching: Caching, for example, after a user logs in, his user information, roles, and permissions do not need to be checked every time, which can improve efficiency
    Concurrency: Shiro supports concurrent verification of multi-threaded applications, that is, If you open another thread in one thread, the permissions can be automatically propagated.
    Testing: Provide testing support;
    Run As: Allow one user to pretend to be another user (if they allow it) to access;
    Remember Me: Remember me, this is a very common function, that is, after logging in once, you don’t need to log in next time

    Shiro architecture (external)

    From the outside Shiro, that is, observe how to use shiro to complete the work from the perspective of the application:

    How to use the Apache Shiro security framework in Java

    subject: The object that the application code directly interacts with is Subject, which means that the core of Shiro's external API is Subject, Subject represents the current user. This user is not necessarily a specific person. Anything that interacts with the current application is Subject, such as web crawlers, robots, etc. All interactions with Subject will be delegated to SecurityManager; Subject is actually A facade, SecurityManageer is the actual executor
    SecurityManager: Security Manager, that is, all security-related operations will interact with SecurityManager, and it manages all Subjects. It can be seen that it is the core of Shiro and is responsible for Interact with other components of Shiro, which is equivalent to the role of SpringMVC's
    DispatcherServlet
    Realm: Shiro obtains security data (such as users, roles, permissions) from Realm, that is to say, the SecurityManager wants to verify the user's identity, then it It is necessary to obtain the corresponding user from Realm for comparison to determine whether the user's identity is legal; it is also necessary to obtain the user's corresponding role and permissions from Realm to verify whether the user's operation can be carried out. Realm can be regarded as a DataSource;

    Shiro Architecture (internal)

    How to use the Apache Shiro security framework in Java

    subject: Any 'user' who can interact with the application;
    Security Manager: Equivalent to the DispatcherServlet in SpringMVC; is Shiro's At the heart, all specific interactions are controlled through the Security Manager, which manages all Subjects and is responsible for authentication, authorization, session, and cache management.

    Authenticator: Responsible for Subject authentication and is an extension point , you can customize the implementation; you can use the authentication strategy (AuthenticationStrategy), that is, under what circumstances is the user authentication passed;
    Authorizer: Authorizer, that is, the access controller, is used to determine whether the subject has the authority to perform the corresponding operation; that is, Controls the functions that users can access in the application;
    Realm: There can be one or more realms, which can be considered as security entity data sources, that is, used to obtain security entities, which can be implemented using DBC or memory. Implementation, etc., are provided by users; so generally in applications, you need to implement your own realm
    SessionManager: a component that manages the Session life cycle, and Shiro can not only be used in the Web environment, but also in the ordinary JavaSE environment.
    CacheManager: Cache controller to manage caches such as users, roles, permissions, etc.; because these data are rarely accessed, access performance can be improved after being cached;
    Cryptography: Cryptozoology module , Shiro has improved some common encryption components for password encryption, decryption, etc.

    2. Quick Start

    1. Copy the case

    1. Follow the official website prompts to find the Quick Start Case GitHub address: shiro/samples/quickstart/

    How to use the Apache Shiro security framework in Java

    #2. Create a new Maven project, delete its src directory, and use it as the parent project

    3. Create a new Maven module in the parent project

    4. Copy the dependencies in the quick start case POM.xml file

    <dependencies>
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-core</artifactId>
                <version>1.4.1</version>
            </dependency>
     
            <!-- configure logging -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>jcl-over-slf4j</artifactId>
                <version>1.7.29</version>
            </dependency>
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
                <version>1.7.29</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
        </dependencies>

    5. Copy the log4j.properties under the resource in the quick start case

    6. Copy the shiro.ini file

    7. Copy the Quickstart.java file

    8. Run and start Quickstart.java

    How to use the Apache Shiro security framework in Java

    2. Analyze the code

    public class Quickstart {
        private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
        public static void main(String[] args) {
            //工厂模式,通过shiro.ini配置文件中的信息,生成一个工厂实例
            Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
            SecurityManager securityManager = factory.getInstance();
            SecurityUtils.setSecurityManager(securityManager);
            //获取当前的用户对象Subject
            Subject currentUser = SecurityUtils.getSubject();
            //通过当前用户拿到session
            Session session = currentUser.getSession();
            session.setAttribute("someKey", "aValue");
            String value = (String) session.getAttribute("someKey");
            if (value.equals("aValue")) {
                log.info("Subject=>session[" + value + "]");
            }
            //判断当前的用户是否被认证
            if (!currentUser.isAuthenticated()) {
                //Token :令牌,没有获取,随机
                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) {
                    //意外情况 ? 错误 ?
                }
            }
            //打印其标识主体(在这种情况下,为用户名)
            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 &#39;drive&#39; the winnebago with license plate (id) &#39;eagle5&#39;.  " +
                        "Here are the keys - have fun!");
            } else {
                log.info("Sorry, you aren&#39;t allowed to drive the &#39;eagle5&#39; winnebago!");
            }
            //注销
            currentUser.logout();
            //退出
            System.exit(0);
        }
    }

    3. SpringBoot integrates Shiro

    1. Write a test environment

    1. Create a new springboot module in the parent project

    How to use the Apache Shiro security framework in Java

    2. Import the dependencies of SpringBoot and Shiro integration package

     <!--SpringBoot 和 Shiro 整合包-->
            <dependency>
                <groupId>org.apache.shiro</groupId>
                <artifactId>shiro-spring</artifactId>
                <version>1.4.1</version>
            </dependency>

    The following is the three major elements for writing configuration files
    Shiro

    Subject user-> ShiroFilterFactoryBean
    SecurityManager manages all users-> DefaultWebSecurityManager
    Realm connection data

    The order of object creation in actual operation: realm -> securityManager -> subject

    3. Write a custom realm, which needs to inherit AuthorizingRealm

    //自定义的 UserRealm        extends AuthorizingRealm
    public class UserRealm extends AuthorizingRealm {
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //打印一个提示
            System.out.println("执行了授权方法");
            return null;
        }
     
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //打印一个提示
            System.out.println("执行了认证方法");
            return null;
        }
    }

    4. Create a new A ShiroConfig configuration file

    @Configuration
    public class ShiroConfig {
     
        //ShiroFilterFactoryBean:3
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebsecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebsecurityManager);
            return bean;
        }
        //DefaultWebSecurityManager:2
        @Bean(name="securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
            //关闭UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
        //创建realm 对象,需要自定义类:1
        @Bean(name="userRealm")
        public UserRealm userRealm(){
            return new UserRealm();
        }
    }

    5. Test successful!

    How to use the Apache Shiro security framework in Java

    2. Use

    1. Login interception

    Add the login request that needs to be intercepted in the getShiroFilterFactoryBean method

    @Configuration
    public class ShiroConfig {
     
        //ShiroFilterFactoryBean:3
        @Bean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebsecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebsecurityManager);
            //添加shiro的内置过滤器
            /*
                anon : 无需认证,就可以访问
                authc : 必须认证了才能访问
                user : 必须拥有 “记住我” 功能才能用
                perms : 拥有对某个资源的权限才能访问
                role : 拥有某个角色权限才能访问
             */
     
            filterMap.put("/user/add","authc");
            filterMap.put("/user/update","authc");
            //拦截
            Map<String,String> filterMap=new LinkedHashMap<>();
            filterMap.put("/user/*","authc");
            bean.setFilterChainDefinitionMap(filterMap);
     
    //        //设置登录的请求
    //        bean.setLoginUrl("/toLogin");
            return bean;
        }

    Test: Clicking the add link will not jump to the add page, but to the login page. The interception is successful

    How to use the Apache Shiro security framework in Java

    2. User authentication

    1. Write a login method in the Controller layer

    //登录的方法
        @RequestMapping("/login")
        public String login(String username, String password, Model model) {
            //获取当前用户
            Subject subject = SecurityUtils.getSubject();
            //封装用户的登录数据,获得令牌
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            //登录 及 异常处理
            try {
                //执行用户登录的方法,如果没有异常就说明OK了
                subject.login(token);
                return "index";
            } catch (UnknownAccountException e) {
                //如果用户名不存在
                System.out.println("用户名不存在");
                model.addAttribute("msg", "用户名错误");
                return "login";
            } catch (IncorrectCredentialsException ice) {
                //如果密码错误
                System.out.println("密码错误");
                model.addAttribute("msg", "密码错误");
                return "login";
            }
        }
    }

    2. Test

    How to use the Apache Shiro security framework in Java

    It can be seen that the AuthenticationInfo method in the custom UserRealm is first executed, and then Perform login-related operations

    3. Modify the doGetAuthenticationInfo method in UserRealm

    //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            //打印一个提示
            System.out.println("执行了认证方法");
            // 用户名密码
            String name = "root";
            String password = "123456";
            //通过参数获取登录的控制器中生成的 令牌
            UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
            //用户名认证
            if (!token.getUsername().equals(name)){
                // return null UnKnownAccountException
                return null;
            }
            //密码认证, Shiro 自己做,为了避免和密码的接触
            //最后返回一个 AuthenticationInfo 接口的实现类,这里选择 SimpleAuthenticationInfo
            // 三个参数:获取当前用户的认证 ; 密码 ; 认证名
            return new SimpleAuthenticationInfo("", password, "");
        }
    }

    4. Test and enter the wrong password

    How to use the Apache Shiro security framework in Java

    How to use the Apache Shiro security framework in Java

    Enter the correct password to log in successfully

    4. Shiro integrates Mybatis

    1. Import dependencies

    <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.19</version>
            </dependency>
     
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
     
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.12</version>
            </dependency>
           <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.1.1</version>
            </dependency>

    2. Create a new application .yml

    spring:
      datasource:
        username: root
        password: 123456
        url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource
     
        #Spring Boot 默认是不注入这些属性值的,需要自己绑定
        #druid 数据源专有配置
        initialSize: 5
        minIdle: 5
        maxActive: 20
        maxWait: 60000
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: SELECT 1 FROM DUAL
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
     
        #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
        #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
        #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
        filters: stat,wall,log4j
        maxPoolPreparedStatementPerConnectionSize: 20
        useGlobalDataSourceStat: true
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
    mybatis:
      type-aliases-package: com.huang.pojo
      mapper-locations: classpath:mybatis/mapper/*.xml

    3. In application.properties

    mybatis.type-aliases-package=com.longdi.pojo
    mybatis.mapper-locations=classpath:mapper/*.xml

    4.Import dependencies

    <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.10</version>
                <scope>provided</scope>
            </dependency>

    5.Write User class

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
            private int id;
            private String name;
            private String pwd;
            private String perms;
    }

    6.Write UserMapper

    @Repository
    @Mapper
    public interface UserMapper {
        public User  queryUserByName(String name);
     
    }

    7. Write UserMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
     
    <mapper namespace="com.longdi.mapper.UserMapper">
     
        <select id="queryUserByName" resultType="User" parameterType="String">
            select * from mybatis.user where name=#{name}
        </select>
     
    </mapper>

    8. Service layer

    UserService interface:

    public interface UserService {
        public User queryUserByName(String name);
    }

    9. Write the interface implementation class UserServiceImpl

    @Service
    public class UserServiceImpl implements UserService{
     
        @Autowired
        UserMapper userMapper;
     
        @Override
        public User queryUserByName(String name) {
            return userMapper.queryUserByName(name);
        }
    }

    10. Test in ShiroSpringbootApplicationTests

    @SpringBootTest
    class ShiroSpringbootApplicationTests {
        @Autowired
        UserServiceImpl userService;
        @Test
        void contextLoads() {
            System.out.println(userService.queryUserByName("longdi"));
        }
    }

    11. Successfully connect to the database

    5. Implement request authorization

    1. Modify in the ShiroConfig class

    How to use the Apache Shiro security framework in Java

    2. Controller jump

    How to use the Apache Shiro security framework in Java

    3. Login interception authorization, test successful

    How to use the Apache Shiro security framework in Java

    How to use the Apache Shiro security framework in Java

    4. Write the authorization doGetAuthorizationInfo method

    How to use the Apache Shiro security framework in Java

    ##5. Request authorization test successfully

    6. Shiro integrates Thymeleaf

    1. Import dependencies

    <!--shiro和thymeleaf整合-->
            <dependency>
                <groupId>com.github.theborakompanioni</groupId>
                <artifactId>thymeleaf-extras-shiro</artifactId>
                <version>2.0.0</version>
            </dependency>

    2. Integrate ShiroDialect

    How to use the Apache Shiro security framework in Java##3.index.html

    How to use the Apache Shiro security framework in Java4. Test

    How to use the Apache Shiro security framework in Java5. Put session

    How to use the Apache Shiro security framework in Java in the authentication. 6. Modify index. html

    The above is the detailed content of How to use the Apache Shiro security framework in Java. For more information, please follow other related articles on the PHP Chinese website!

    Statement:
    This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete