目錄
一、Shiro簡介:
shiro功能:
Shiro架構(外部)
Shiro架構(內部)
二、快速入門
#1.拷貝案例
2.分析程式碼
三、SpringBoot 整合Shiro
#1.寫測試環境
2.使用
1.登入攔截
#2.用戶認證
##1.在ShiroConfig類別中修改
1.導入依賴
首頁 Java java教程 Java中Apache Shiro安全框架怎麼用

Java中Apache Shiro安全框架怎麼用

Apr 18, 2023 pm 07:40 PM
java apache shiro

    一、Shiro簡介:

    Apache Shiro是一個Java的安全性(權限)框架。
    Shiro 可以非常容易的開發出足夠好的應用,其不僅可以用在JavaSE環境,也可以用在JavaEE環境。 Shiro可以完成,認證,授權,加密,會話管理,Web集成,快取等。

    Java中Apache Shiro安全框架怎麼用

    shiro功能:

    Java中Apache Shiro安全框架怎麼用

    #Authentication:認證、登錄,驗證用戶是不是擁有對應的身份;
    Authorization:授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限,即判斷用戶能否進行什麼操作,如:驗證某個用戶是否擁有某個角色,或者細粒度的驗證某個使用者對某個資源是否具有某個權限!
    Session Manager:會話管理,即使用者登入後就是第一次會話,在沒有退出之前,它的所有資訊都在會話中;會話可以是普通的JavaSE環境,也可以是Web環境;
    Cryptography:加密,保護資料的安全性,如密碼加密儲存到資料庫中,而不是明文儲存;Web Support: Web支持,可以非常容易的整合到Web環境;
    Caching:緩存,例如使用者登入後,其使用者訊息,擁有的角色、權限不必每次去查,這樣可以提高效率
    Concurrency: Shiro支援多執行緒應用的並發驗證,即,如在一個線程中開啟另一個線程,則將權限自動的傳播過去
    Testing:提供測試支援;
    Run As:允許一個使用者假裝為另一個使用者(如果他們允許)的身份進行存取;
    Remember Me:記住我,這個是非常常見的功能,即一次登入後,下次再來的話不用登入了

    Shiro架構(外部)

    #從外部來看Shiro,也就是從應用程式角度來觀察如何使用shiro完成工作:

    Java中Apache Shiro安全框架怎麼用

    subject:應用程式碼直接互動的物件是Subject,也就是說Shiro的對外API核心就是Subject,Subject代表了當前的用戶,這個用戶不一定是一個具體的人,與當前應用交互的任何東西都是Subject,如網絡爬蟲,機器人等,與Subject的所有交互都會委託給SecurityManager; Subject其實是一個門面,SecurityManageer才是實際的執行者
    SecurityManager: 安全管理器,即所有與安全相關的操作都會與SercurityManager交互,並且它管理著所有的Subject,可以看出它是Shiro的核心,它負責與Shiro的其他元件進行交互,它相當於SpringMVC的
    DispatcherServlet的角色
    Realm: Shiro從Realm取得安全資料((如用戶,角色,權限),就是說SecurityManager要驗證使用者身份,那麼它需要從Realm 取得對應的使用者進行比較,來決定使用者的身分是否合法;也需要從Realm得到使用者對應的角色、權限,進行驗證使用者的操作是否能夠進行,可以把Realm看成DataSource;

    Shiro架構(內部)

    Java中Apache Shiro安全框架怎麼用

    subject:任何可以與應用程式互動的'用戶';
    Security Manager:相當於SpringMVC中的DispatcherServlet;是Shiro的心臟,所有具體的交互都透過Security Manager進行控制,它管理者所有的Subject,且負責進行認證,授權,會話,及緩存的管理.

    Authenticator:負責Subject認證,是一個擴展點,可以自訂實作;可以使用認證策略(AuthenticationStrategy),即什麼情況下算用戶認證通過了;
    Authorizer: 授權器,即存取控制器,用來決定主體是否有權限進行相應的操作;即控制用戶能存取應用程式中的那些功能;
    Realm:可以有一個或多個的realm,可以認為是安全實體資料來源,也就是用於取得安全實體的,可以用DBC實現,也可以是記憶體實作等等,由使用者提供;所以一般在應用中都需要實作自己的realm
    SessionManager: 管理Session生命週期的元件,而Shiro不只可以用在Web環境,也可以用在普通的JavaSE環境中
    CacheManager:快取控制器,來管理如用戶,角色,權限等快取的;因為這些資料基本上很少以受,成到快取中後可以提高存取的效能;
    Cryptography:密碼模組,Shiro提高了一些常見的加密組件用於密碼加密,解密等

    二、快速入門

    #1.拷貝案例

    1.按照官網提示找到快速入門案例GitHub地址:shiro/samples/quickstart/

    Java中Apache Shiro安全框架怎麼用

    #2.新建一個Maven 工程,刪除其src 目錄,將其作為父工程

    #3.在父工程中新建一個Maven 模組

    4.複製快速入門案例POM.xml 檔案中的依賴

    <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.把快速入門案例中的resource 下的log4j.properties複製下來

    6.複製一下shiro.ini檔案

    7.複製一下Quickstart.java檔案

    8.運行啟動Quickstart.java

    Java中Apache Shiro安全框架怎麼用

    2.分析程式碼

    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);
        }
    }
    登入後複製

    三、SpringBoot 整合Shiro

    #1.寫測試環境

    1.在剛剛的父專案中新建一個springboot 模組

    Java中Apache Shiro安全框架怎麼用

    2.導入SpringBoot 和Shiro 整合包的依賴

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

    以下是寫設定檔
    Shiro 三大要素

    Subject 使用者-> ShiroFilterFactoryBean
    SecurityManager 管理所有使用者-> DefaultWebSecurityManager
    #Realm 連線資料

    #實際操作中物件建立的順序: realm -> securityManager -> subject

    3.編寫自訂的realm ,需要繼承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.新建一個ShiroConfig設定檔

    @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.測試成功!

    Java中Apache Shiro安全框架怎麼用

    2.使用

    1.登入攔截

    在getShiroFilterFactoryBean方法中加入需要攔截的登入請求

    @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;
        }
    登入後複製

    測試:點選add鏈接,不會跳到add 頁面,而是跳到登入頁,攔截成功

    Java中Apache Shiro安全框架怎麼用

    #2.用戶認證
    ##1.在Controller層寫一個登入的方法

    //登录的方法
        @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.測試

    Java中Apache Shiro安全框架怎麼用

    可以看出是先執行了自訂的UserRealm中的AuthenticationInfo方法,再執行登入相關的操作

    3.修改UserRealm中的doGetAuthenticationInfo方法

    //认证
        @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.測試,輸入錯誤的密碼

    Java中Apache Shiro安全框架怎麼用

    Java中Apache Shiro安全框架怎麼用

    輸入正確的密碼,即可登入成功

    四、Shiro整合Mybatis

    1.匯入依賴

    <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.新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.在application.properties

    mybatis.type-aliases-package=com.longdi.pojo
    mybatis.mapper-locations=classpath:mapper/*.xml
    登入後複製

    4.導入依賴

    <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.10</version>
                <scope>provided</scope>
            </dependency>
    登入後複製

    5.寫User類別

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
            private int id;
            private String name;
            private String pwd;
            private String perms;
    }
    登入後複製

    6.寫UserMapper

    @Repository
    @Mapper
    public interface UserMapper {
        public User  queryUserByName(String name);
     
    }
    登入後複製

    7.寫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層

    UserService介面:

    public interface UserService {
        public User queryUserByName(String name);
    }
    登入後複製

    9.寫介面實作類別UserServiceImpl

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

    10.在ShiroSpringbootApplicationTests測試

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

    11.成功連接資料庫

    #五、實作請求授權

    ##1.在ShiroConfig類別中修改

    Java中Apache Shiro安全框架怎麼用#2.controller跳轉

    Java中Apache Shiro安全框架怎麼用#3.登入攔截授權,測試成功

    Java中Apache Shiro安全框架怎麼用

    Java中Apache Shiro安全框架怎麼用4.編寫授權doGetAuthorizationInfo方法

    Java中Apache Shiro安全框架怎麼用#5.請求授權測試成功

    六、Shiro整合Thymeleaf

    1.導入依賴

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

    2.整合ShiroDialect

    Java中Apache Shiro安全框架怎麼用#3.index.html

    Java中Apache Shiro安全框架怎麼用4.測試

    Java中Apache Shiro安全框架怎麼用5.在認證裡放session

    ##6.修改index. htmlJava中Apache Shiro安全框架怎麼用

    以上是Java中Apache Shiro安全框架怎麼用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    本網站聲明
    本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    AI Hentai Generator

    AI Hentai Generator

    免費產生 AI 無盡。

    熱門文章

    R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
    2 週前 By 尊渡假赌尊渡假赌尊渡假赌
    倉庫:如何復興隊友
    4 週前 By 尊渡假赌尊渡假赌尊渡假赌
    Hello Kitty Island冒險:如何獲得巨型種子
    3 週前 By 尊渡假赌尊渡假赌尊渡假赌

    熱工具

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    SublimeText3漢化版

    SublimeText3漢化版

    中文版,非常好用

    禪工作室 13.0.1

    禪工作室 13.0.1

    強大的PHP整合開發環境

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級程式碼編輯軟體(SublimeText3)

    Java 中的平方根 Java 中的平方根 Aug 30, 2024 pm 04:26 PM

    Java 中的平方根

    Java 中的完美數 Java 中的完美數 Aug 30, 2024 pm 04:28 PM

    Java 中的完美數

    Java 中的隨機數產生器 Java 中的隨機數產生器 Aug 30, 2024 pm 04:27 PM

    Java 中的隨機數產生器

    Java中的Weka Java中的Weka Aug 30, 2024 pm 04:28 PM

    Java中的Weka

    Java 中的阿姆斯壯數 Java 中的阿姆斯壯數 Aug 30, 2024 pm 04:26 PM

    Java 中的阿姆斯壯數

    Java 中的史密斯數 Java 中的史密斯數 Aug 30, 2024 pm 04:28 PM

    Java 中的史密斯數

    Java Spring 面試題 Java Spring 面試題 Aug 30, 2024 pm 04:29 PM

    Java Spring 面試題

    突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

    突破或從Java 8流返回?

    See all articles