標籤: 包裝設計

  • Suzuki Swift跟進導入輕油電動力 小改款車型預計4月日本首發

    摘錄自2020年3月18日ETtoday報導

    2020年暫訂沒有改款幅度較大的新世代車型問世,但近年來憑藉著堅強的「小車大軍」席捲市場的Suzuki,也著手針對品牌車款進行小改款更新。

    根據日媒報導,即將在4月推出小改款車型的Swift,在動力規格上,如無意外的話,Suzuki應也會擴大輕油電系統的應用範圍,進而在既有的1.0升渦輪、1.2升自然進氣動力設定之外,追加1.2升輕油電動力車型;同時同宗性能車型Swift Sport預計也將會在1.4升渦輪汽油引擎當中,額外追加48V輕油電動力架構,藉此改善該車款在油耗以及排污的各項表現。

    回到台灣國內,雖說受限於歐盟排放法規,台灣Suzuki早些時候已宣布停止Swift Sport的導入事宜,但一般常規Swift仍具備相當不俗的銷售潛力;為此外界一般也不排除,小改款Swift將會是台灣Suzuki下一批積極爭取導入的戰略車款。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 用剛果童工挖鈷致死或殘 5科技巨頭挨告

    摘錄自2019年12月17日聯合報報導

    特斯拉、蘋果、微軟、戴爾、Google母公司字母(Alphabet)以共謀罪名被告上法庭。這是科技業首次因其鈷來源,共同面臨法律訴訟。

    代表剛果民主共和國14個家庭擔任原告的美國人權組織「國際權利倡議」(International Rights Advocates)15日提告五家全球大型科技公司,指強迫勞動的體系導致這些家庭的小孩死亡或重傷,而五家科技業者是這個體系的一部分。

    這起訴訟說,案件裡的兒童,最小的才6歲,因為出身赤貧家庭,不得不休學到嘉能可的礦坑挖鈷。他們每周要工作六天,有些人領的日薪低到只有1.5美元(約台幣45元)。

    鈷是製造科技產品內部可重複使用鋰電池的必要材料。全球一半以上的鈷產自剛果民主共和國。根據歐盟執委會2018年的一份研究,未來10年全球鈷需求料將每年增加7%到13%。原告主張,挨告的科技業者全都有能力徹底整頓旗下鈷供應鏈,以確保更安全的工作條件。

    本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 【服務器】VMware Workstation Pro虛擬機搭建本地服務器CentOs7和寶塔面板(保姆式教程)

    【服務器】VMware Workstation Pro虛擬機搭建本地服務器CentOs7和寶塔面板(保姆式教程)

    內容繁多,請耐心跟着流程走,在過程中遇到問題請在下面留言(我只是小白,請專業人士噴輕點)。

    前言

    這幾天一直在複習thinkphp5.1,學習環境是phpStudy8.1,但是遇到了文件有緩存的問題(thinkphp5.1.39,修改文件后刷新沒有效果那種,需要隔幾分鐘才正常),百度也沒有解決方法,搞了幾天,一直沒解決,就氣着去折騰本地虛擬機服務器,使用阿里雲的CentOs7鏡像(本站的服務器也是阿里雲的CentOs7,運維環境也是寶塔哦),運維環境是寶塔面板

    說到寶塔就有一些故事了,買服務器的時候是想用windows server2008的,配置了IIS一段時間,搞不定,然後往nginx方向走,又搞不定,後來用windows寶塔面板,還是搞不定,不管怎麼折騰都沒辦法搞定,網站一直打不開,然後就轉CentOs7了,安裝寶塔,配置域名,訪問域名,網站就可以显示了,回想當初,不知道自己腦子抽了哪條經。

    工具

    • VMware Workstation Pro 15.5.5(虛擬機,自己去下載安裝哦,安裝步驟:下一步,我同意,修改安裝路徑,下一步,完成)

    • CentOs7(iso鏡像,推薦使用IDM或者迅雷下載,鏡像大小4.6GB上下)
      阿里雲鏡像:http://mirrors.aliyun.com/centos/7.8.2003/isos/x86_64/

    • Xshell(用於連接虛擬機,方便使用Linux命令,是一個遠程工具,右鍵就可以複製粘貼哦,還可以拉滾動條。)

    查看並保持vmnet8 ip

    本地vmnet8 ip

    查看本地的vmnet8 ip(安裝好虛擬機后才會自動生成的),打開cmd輸入ipconfig
    按win鍵+R,輸入cmd,回車就能打開cmd

    或者按win鍵+S,搜索“cmd”,也能打開“命令提示符”

    還有左下角的“田”形右鍵,然後選擇“Windows Powershell”;
    還有Git的Git Bash等等。。。。。。。。。。。。。。。。

    輸入ipconfig后,就显示下面界面

    這裏主要的內容是以太網適配器VIware Network Adapter VInet8,把細框里的IPv4地址子網掩碼默認網關(我這裏沒有,我也不知道為什麼)用文本記下來,或者不關這個窗口,後面要用到的。

    虛擬機vmnet8 ip

    虛擬機裏面的虛擬網絡需要設置一下虛擬機裏面的虛擬網絡需要處理一下虛擬機裏面的虛擬網絡需要編輯一下

    下圖標記2的地方,勾勾要去掉,去掉之後點擊NAT設置,查看虛擬機的vmnet8 ip,把紅框里的子網IP子網掩碼默認網關用文本記下來,然後點擊確定。

    現在整理一下要用文本記下來的東西

    創建虛擬機

    點擊創建新的虛擬機

    點擊自定義,下一步。

    選擇虛擬機版本,我這裡是15.5.5,下一步

    點擊稍後安裝操作系統,下一步。

    選擇Linux操作系統,現在安裝的是entOs7,所以版本選擇CentOs7 64位,下一步。

    虛擬機名稱隨意,可以中文,這裏我寫的是服務器ip名(可以重命名的),為了方便定位,不用我說都懂的啦,從左邊欄就可以看出100、101、102沒有102,哎?我跳過102了?我是把流程走一遍再碼字的,碼字的時候,服務器已經ok了,不過問題不大,下一步。。。。

    默認(本站的核心是2個,但是我100、101都是1個核心,這裏默認1個核心夠用了),本地服務器,也就自己一個人訪問,而且這裏配置是跟本機電腦配置有關的,服務器一核心足矣(只要電腦帶得動,給八核我也沒意見),下一步。

    默認(本站的內存是1GB,但是我100、101都是2GB,這裏默認1GB夠用了),同上(如果在阿里雲買服務器,我建議是1核心2GB內存哦),下一步。

    點擊使用網絡地址轉換(NAT),下一步。

    默認,下一步。

    默認,下一步。

    默認,下一步。

    默認(磁盤大小自己改,20GB實際上夠了,下面選項默認),下一步。

    默認,下一步。

    點擊自定義硬件

    點擊打印機,然後點擊移除

    跟着数字的步驟走(步驟3:選擇下載好的CentOs7鏡像,我個人是推薦放在服務器根目錄下,看我圖中的路徑,這裏不明白要留言哦)。

    點擊完成

    安裝CentOs7系統

    點擊開啟此虛擬機

    這裏說一下,默認選中的是Test this this media & install CentOS 7(白色字體是選中狀態),按方向鍵↑然後回車(如果按鍵沒效果,需要把鼠標點一下虛擬機显示屏)。

    中文在最下面,滾下去或者拉到下面才看到(下面的搜索chinese),點擊繼續

    這裏看一下自己的日期和時間是不是亞洲/上海 時區,不是的話自己進去調一下(百度)。

    點擊軟件選擇

    把紅框里的兩個勾勾點上,完成。

    點擊安裝位置

    點擊我要配置分區,完成。

    點擊點這裏自動創建他們,完成。

    默認,/boot(啟動文件),swap(交換分區,類似windows虛擬內存。看內存總大小,如果內存足夠大,這個空間就要設置很大,如果內存小於2G,那麼這個空間設置成內存的2倍大小。),/(根分區),完成。

    點擊接受更改

    點擊網絡和主機名

    打開以太網,修改主機名(也闊以使用默認的啦),然後點擊應用(點完應用后看看以太網是不是關閉了,如果關閉了再點開),完成。

    點擊開始安裝

    點擊ROOT密碼

    設置密碼,我這裏設置123456(本機的,起個好記的就好),完成(點兩次)。

    等待安裝(根據自己的需求去創建用戶吧,但是創建后可能某些操作需要root權限,不折騰就不要創了,昨晚搞CentOs8服務器差點崩潰,CentOs8是規定要創建用戶的,CentOs7和CentOs8就跟windows7和windows10一樣)。

    安裝完畢,點擊重啟。

    選擇第一個。

    我的用戶名是root,密碼123456
    輸入用戶名root,回車。

    輸入密碼123456(不可見的,輸入就行了),回車。

    噔噔噔噔,革命成功

    配置服務器靜態ip(需要配置服務器動態ip的自己百度一下)

    到了這一步,你已經回不了頭了,還學會一丟丟Linux命令,建議多去看看Linux命令

    打開目錄:cd /etc/sysconfig/network-scripts/(複製粘貼就好,這個複製粘貼有點麻煩,找不到的就手敲,正是這樣才要用Xshell工具來遠程,得先配置ip,忍一忍吧),回車。

    我這裏显示的是ifcfg-ens33,這裏要說一下,我百度過,有些是32,也有1667777,先用cd /etc/sysconfig/network-scripts/進入目錄,然後ll显示列表(ls也可以显示列表,只显示列表名)。

    編輯ifcfg-ens33:vi ifcfg-ens33(vi:進入編輯模式,文件名別敲錯。),回車。

    i 字母鍵進入編輯模式(如果不显示下圖的,肯定是vi ifcfg-ens33輸入錯了,自己檢查一下,退出vi方法:按Esc(注意左下角),輸入:q!(不保存退出))。

    看圖IPADDR=192.168.157.103NETMASK=255.255.255.0GATEWAY=192.168.157.2,這裏不建議複製粘貼了,好好敲,我擔心會亂(如果一定要複製粘貼的話,先把裏面的複製出來,加上IPADDR、NETMASK、GATEWAY再粘貼回去,不知道能不能明白我的意思,咱們還是敲吧!!!)。

    保存並退出:按Esc鍵,然後輸入:wq(必須小寫),回車。

    重啟網絡:systemctl restart network,回車。
    查看ip:ip addr, 回車。
    出現下圖就可以了,萬歲。

    配置本地的網絡(只需要配置一次)

    這是本地訪問虛擬機要配置的,文本中記下來的本機ip用這裏(因為我這沒有默認網關,所以不填)。

    使用Xshell連接虛擬機服務器(右鍵就可以複製粘貼哦)

    新建會話,這裏隧道要取消轉發X11連接到:(可能會有人奇怪,為什麼這張步驟和下面步驟在正常思路來說調換了,我其實是忘了,後面才補回來的)。

    新建會話,輸入名稱192.168.157.103(輸入名稱后,下面的主機也是同步的。),然後點擊連接。

    出現這個彈窗就說明99.99%成功了,如果沒有就說明配置出錯,大概率在上一個步驟[配置本地的網絡(點擊跳轉)][60]

    輸入用戶名root

    輸入用戶名123456

    okay。

    安裝寶塔面板

    寶塔官網:https://www.bt.cn/
    寶塔Linux面板命令大全:https://www.bt.cn/btcode.html(一定要多看)

    這裏標註幾個常用的命令(本文章用到的):cd(不用說了吧)、clear(清屏,也可以用Ctrl+L)、ll(當前列表,詳細的展示列表),ls(當前列表,簡潔的展示列表)、vi 文件名(編輯文件,按Esc::wq保存並退出、:q(退出)、:q!強制不保存並退出)。

    安裝

    安裝腳本:yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh
    PS:此腳本從官方複製過來的時間為2020年6月19日,僅限CentOs系統,如果距離已久,請到官網複製

    右鍵隨意複製粘貼,Xshell工具的好處(佛主:https://www.kancloud.cn/jiangguowu/kfjsdkfjskd/1076752)。

    DO you want to install Bt Panel tothe /www directory now?(y/n):(現在是否要將Bt面板安裝到/www目錄?(是/否):)。
    按y,回車。

    寶塔面板訪問地址:http://192.168.157.103:8888/7a81976f119.137.3.117換成192.168.157.103自己設置的服務器ip(別傻了,只有本地才能訪問)。

    username: yq0g4uxd
    password: c937d4a9

    是闊一。

    點擊一鍵安裝(也可以不選擇,然後自己去左邊的軟件商店自己選擇安裝)。

    建議設置一下安全入口面板用戶面板密碼(只能設置8位數,為了方便,我強行使用命令行將密碼設置為123456,命令:cd /www/server/panel && python tools.py panel 123456,更多的寶塔命令請到寶塔Linux面板命令大全查看:https://www.bt.cn/btcode.html)

    報錯、錯誤、問題大雜燴(此目錄處理教程中遇到的問題,請在下面留言)

    安裝寶塔 -> 14: curl#6 – “Could not resolve host: mirrorlist.centos.org; 未知的錯誤

    打開:vi /etc/resolv.conf
    加入:nameserver 8.8.8.8nameserver 8.8.4.4

    完美結束!!!

    圖片太多,碼字的時候都卡了,大概68張圖片,感覺還是錄製視頻好啊

    如果有錯誤的地方,歡迎糾正。

    我已經想好下一篇的文章了,出一個寶塔面板使用教程。

    原文鏈接:https://blog.langting.top/archives/117.html

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 一文梳理JavaScript中的this

    一文梳理JavaScript中的this

    最近零零碎碎看了許多關於this的文章,本着“好記性不如爛筆頭”的思想,特在這裏整理一下this有關的知識點。【長文警告!!!】

    接下來,筆者將按照以下目錄對this進行闡述:

    • this是什麼?
    • this指向
      • this在全局範圍內
      • this在對象的構造函數內
      • this在對象的方法內
      • this在簡單函數內
      • this在箭頭函數內
      • this在一個事件偵聽器內
    • this綁定規則
      • 默認綁定
      • 隱式綁定
      • 显示綁定(this修改)
      • 優先級
    • 箭頭函數

    1. this是什麼?

    this是JavaScript的一個關鍵字,但它時常矇著面紗讓人無法捉摸,許多對this不明就裡的同學,常常會有這樣的錯誤認知:

    • this在函數內指向函數自身

      •   function foo(num){
              console.log("foo: " + num);
          
              //記錄foo被調用次數
              this.count++;
          }
          foo.count = 0;
          for(let i=0; i<10; i++){
              if(i > 5){
                  foo(i);
              }
          }
          console.log(foo.count); // 0, this並沒有指向foo函數,foo.count沒有進行任何操作
        
    • this在函數內指向函數的作用域

      •   function foo(){
              var a = 2;
              this.bar();
          }
          function bar(){
              console.log(this.a);
          }
          foo();// undefined, window對象沒有bar這一屬性
        

    2. this指向

    this的指向取決於他所處的環境. 大致上,可以分為下面的6種情況:

    • this在全局範圍內
    • this在對象的構造函數內
    • this在對象的方法內
    • this在一個簡單的函數內
    • this在箭頭函數內
    • this在一個事件偵聽器內

    2.1 this在全局範圍內

    this在全局範圍內綁定什麼呢?這個相信只要學過JS,應該都知道答案。如果不知道,同學真的應該反思自己的學習態度和方法是否存在問題了。話不多說,直接上代碼,一探究竟,揭開this在全局範圍下的真面目:

    console.log(this); // Window
    

    不出意外,this在全局範圍內指向window對象()。通常, 在全局環境中, 我們很少使用this關鍵字, 因此對它也沒那麼在意. 讓我們繼續看下一個環境.

    2.2 this在對象的構造函數內

    當我們使用new創建構造函數的實例時會發生什麼呢?以這種方式調用構造函數會經歷以下四個步驟:

    • 創建一個空對象;

    • 將構造函數的作用域賦給新對象(this指向了這個新對象),繼承函數的原型;

    • 執行構造函數中的代碼;

    • 返回新對象。

    看完上面的內容,大家想必也知道this在對象的構造函數內的指向了吧!當你使用new關鍵字創建一個對象的新的實例時, this關鍵字指向這個實例 .

    舉個栗子:

    function Human (age) {
        this.age = age;
    }
    let greg = new Human(22);
    let thomas = new Human(24);
    
    console.log(greg); // this.age = 22
    console.log(thomas); // this.age = 24
    
    // answer
    Person { age:22}
    Person { age:24}
    

    2.3 this在對象方法內

    方法是與對象關聯的函數的通俗叫法, 如下所示:

    let o = {
        sayThis(){
            console.log(this);
        }
    }
    

    如上所示,在對象的任何方法內的this都是指向對象本身 .

    好了,繼續下一個環境!

    2.4 this在簡單函數內

    可能看到這裏,許多同學心裏會有疑問,什麼是簡單函數?

    其實簡單函數大家都很熟悉,就像下面一樣,以相同形式編寫的匿名函數也被認為是簡單函數(非箭頭函數)。

    function hello(){
        console.log("hello"+this);
    }
    

    這裏需要注意,在瀏覽器中,不管函數聲明在哪裡,匿名或者不匿名,只要不是直接作為對象的方法,this指向始終是window對象(除非使用call,apply,bind修改this指向)。

    舉個栗子說明一下:

    // 显示函數,直接定義在sayThis方法內,this指向依舊不變
    function simpleFunction() {
        console.log(this);
    }
    
    var o = {
        sayThis() {
            simpleFunction();
        }
    }
    
    simpleFunction(); // Window
    o.sayThis(); // Window
    
    
    // 匿名函數
    var o = {
        sayThis(){
            (function(){consoloe.log(this);})();
        }
    } 
    o.sayThis();// Window
    

    對於初學者來說,this在簡單函數內的表現時常讓他們懵逼不已,難道this不應該指向對象本身?這個問題曾經也出現在我的腦海里過,沒錯,在寫代碼時我也踩過這個坑。

    通常的,當我們要在對象方法內調用函數,而這個函數需要用到this時,我們都會創建一個變量來保存對象中的this的引用. 通常, 這個變量名稱叫做self或者that。具體說下所示:

    const o = {
        doSomethingLater() {
            const self = this;
            setTimeout(function() {
                self.speakLeet();
            }, 1000);
        },
        speakLeet() {
            console.log(`1337 15 4W350M3`);
        }
    }
    
    o.doSomethingLater(); // `1337 15 4W350M3`
    

    心細的同學可能已經發現,這裏的簡單函數沒有將箭頭函數包括在內,那麼下一個環境是什麼想必也能猜到啦,那麼現在進入下一個環境,看看this指向什麼。

    2.5 this在箭頭函數內

    和簡單函數表現不太一樣,this在箭頭函數中總是跟它在箭頭函數所在作用域的this一樣(在它直接作用域). 所以, 如果你在對象中使用箭頭函數, 箭頭函數中的this總是指向這個對象本身, 而不是指向Window.

    下面我們使用箭頭函數,重寫一下上面的案例:

    const o = {
        doSomethingLater() {
            setTimeout(() => this.speakLeet(), 1000);
        },
        speakLeet() {
            console.log(`1337 15 4W350M3`);
        }
    }
    o.doSomethingLater(); // `1337 15 4W350M3`
    

    最後,讓我們來看看最後一種環境 – 事件偵聽器.

    2.6 this在事件偵聽器內

    在事件偵聽器內, this被綁定的是觸發這個事件的元素:

    let button = document.querySelector('button');
    
    button.addEventListener('click', function() {
        console.log(this); // button
    });
    

    3. this綁定規則

    事實上,只要記住上面this在不同環境的綁定值,足以應付大部分工作。然而,好學的同學總是會忍不住想說,為什麼呢?對,為什麼this在這些情況下綁定這些值呢?學習,我們不能只知其然,而不知所以然。所以,現在就讓我們來探尋,this值獲取的真相吧。

    現在,讓我們回憶一下,在講什麼是this的時候,我們說到“this的綁定取決於他所處的環境”。這句話其實不是十分準確,準確的說,this不是編寫時綁定,而是運行時綁定。它依賴於函數調用的上下文條件this綁定和函數聲明的位置無關,反而和函數被調用的方式有關

    當一個函數被調用時,會建立一個活動記錄,也稱為執行環境。這個記錄包含函數是從何處(call-stack)被調用的,函數是 如何被調用的,被傳遞了什麼參數等信息。這個記錄的屬性之一,就是在函數執行期間將被使用的this引用。this實際上是在函數被調用時建立的一個綁定,它指向什麼是完全由函數被調用的調用點來決定的

    僅僅是規則

    現在我們將注意力轉移到調用點 如何 決定在函數執行期間this指向哪裡。

    你必須考察call-site並判定4種規則中的哪一個適用。我們將首先獨立的解釋一下這4種規則中的每一種,之後我們來展示一下如果有多種規則可以適用調用點時,它們的優先級。

    3.1 默認綁定規則

    第一種規則來源於函數調用的最常見的情況:獨立函數調用。可以認為這種this規則是在沒有其他規則適用時的默認規則。我們給它一個稱呼“默認綁定”.

    現在來看這段代碼:

    function foo(){
        console.log(this); 
    }
    var a = 2;
    demo(); // 2
    

    當foo()被調用時,this.a解析為我們的全局變量a。為什麼?因為在這種情況下,對此方法調用的this實施了 默認綁定,所以使this指向了全局對象。

    在我們的代碼段中,foo()是被一個直白的,毫無修飾的函數引用調用的。沒有其他的我們將要展示的規則適用於這裏,所以 默認綁定 在這裏適用。

    如果strict mode在這裏生效,那麼對於 默認綁定 來說全局對象是不合法的,所以this將被設置為undefined。

    'use strict'
    function foo(){
        console.log(this.a); // TypeError: Cannot read property 'a' of undefined
    }
    const a = 1;
    foo();
    
    function foo(){
    	'use strict'
        console.log(this.a); // TypeError: Cannot read property 'a' of undefined
    }
    const a = 1;
    foo();
    

    微妙的是,即便所有的this綁定規則都是完全基於調用點,如果foo()的 內容 沒有在strint mode下執行,對於 默認綁定 來說全局對象是 唯一 合法的;foo()的call-site的strict mode狀態與此無關。

    function foo(){
        console.log(this.a); 
    }
    var a = 1;
    (function(){
    	'use strict';
    	foo(); // 1
    })();
    

    注意: 在代碼中故意混用strict mode和非strict mode通常是讓人皺眉頭的。你的程序整體可能應當不是 Strict 就是非Strict。然而,有時你可能會引用與你的 Strict 模式不同的第三方包,所以對這些微妙的兼容性細節要多加小心。

    3.2 隱式綁定

    另一種要考慮的規則是:調用點是否有一個環境對象(context object),也稱為擁有者(owning)或容器(containing)對象。

    讓我們來看這段代碼:

    function foo() {
        console.log(this.a);
    }
    let o = {
        a: 2,
        foo,
    }
    o.foo(); // 2
    

    這裏,我們注意到foo函數被聲明然後作為對象o的方法,無論foo()是否一開始就在obj上被聲明,還是後來作為引用添加(如上面代碼所示),都是這個 函數 被obj所“擁有”或“包含”。這裏,調用點使用obj環境來引用函數,所以可以說 obj對象在函數被調用的時間點上“擁有”或“包含”這個 函數引用。

    當一個方法引用存在一個環境對象時,隱式綁定 規則會說:是這個對象應當被用於這個函數調用的this綁定。

    只有對象屬性引用鏈的最後一層是影響調用點的。比如:

    function foo(){
        console.log(this.a);
    }
    
    var obj1 = {
        a:2,
        obj2:obj2
    };
    var obj2 = {
        a:42,
        foo:foo
    };
    obj1.obj2.foo(); // 42
    

    隱式綁定的隱患

    當一個 隱含綁定丟失了它的綁定,這通常意味着它會退回到 默認綁定, 根據strict mode的狀態,結果不是全局對象就是undefined。

    下面來看這段代碼:

    function foo(){
        console.log(this.a);
    }
    
    var obj = {
        a:2,
        foo
    };
    var bar = obj.foo;
    var a = "Global variable";
    bar(); // "Global variable"
    

    儘管bar似乎是obj.foo的引用,但實際上它只是另一個foo自己的引用而已。另外,起作用的調用點是bar(),一個直白,毫無修飾的調用,因此 默認綁定 適用於這裏。

    這種情況發生的更加微妙,更常見,更意外的方式,是當我們考慮傳遞一個回調函數時:

    function foo(){
        console.log(this.a);
    }
    
    function doFoo(fn){
    	fn();
    }
    
    var obj = {
        a:2,
        foo,
    };
    var a = "Global variable";
    dooFoo(obj.foo); // "Global variable"
    

    參數傳遞僅僅是一種隱含的賦值,而且因為我們在傳遞一個函數,它是一個隱含的引用賦值,所以最終結果和我們前一個代碼段一樣。同樣的,語言內建,如setTimeout也一樣,如下所示

    function foo(){
        console.log(this.a);
    }
    
    var obj = {
        a:2,
        foo,
    };
    var a = "Global variable";
    setTimeout(obj.foo, 100); // "Global variable"
    

    把這個粗糙的setTimeout()假想實現當做JavaScript環境內建的實現的話:

    function setTimeout(fn, delay){
        // 等待delay毫秒
        fn();
    }
    

    正如我們看到的, 隱含綁定丟失了它的綁定是十分常見的,不管哪一種意外改變this的方式,你都不能真正地控制你的回調函數引用將如何被執行,所以你(還)沒有辦法控制調用點給你一個故意的綁定。但是我們可以使用显示綁定強行固定this。

    3.3 显示綁定

    我們看到隱含綁定,需要我們不得不改變目標對象使它自身包含一個對函數的引用,而後使用這個函數引用屬性來間接地(隱含地)將this綁定到這個對象上。

    但是,如果你想強制一個函數調用使用某個特定對象作為this綁定,而不在這個對象上放置一個函數引用屬性呢?

    js有提供call()、apply()方法,ES5中也提供了內置的方法 Function.prototype.bind,可以引用一個對象時進行強制綁定調用。

    考慮這段代碼:

    function foo(){
        console.log(this.a);
    }
    var obj = {
        a:2,
    };
    foo.call(obj); // 2
    

    通過foo.call(..)使用 明確綁定 來調用foo,允許我們強制函數的this指向obj。

    如果你傳遞一個簡單原始類型值(string,boolean,或 number類型)作為this綁定,那麼這個原始類型值會被包裝在它的對象類型中(分別是new String(..),new Boolean(..),或new Number(..))。這通常稱為“boxing(封箱)”。

    注意: 就this綁定的角度講,call(..)和apply(..)是完全一樣的。它們確實在處理其他參數上的方式不同,但那不是我們當前關心的。

    單獨依靠call和apply,仍然可能出現函數“丟失”自己原本的this綁定,或者被第三方覆蓋等問題。

    但有一個技巧可以避免出現這些問題

    考慮這段代碼:

    function foo(){
        console.log(this.a);
    }
    var obj = {
    	a:2
    };
    var bar = function(){
    	foo.call(obj);
    }
    bar(); // 2
    setTimeout(bar, 100); // 2
    bar.call(window); // 2
    

    我們創建了一個函數bar(),在它的內部手動調用foo.call(obj),由此強制this綁定到obj並調用foo。無論你過後怎樣調用函數bar,它總是手動使用obj調用foo。這種綁定即明確又堅定,該方法被開發者稱為 硬綁定(显示綁定的變種)(hard binding)

    用硬綁定將一個函數包裝起來的最典型的方法,是為所有傳入的參數和傳出的返回值創建一個通道:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    var obj = {
        a:2
    };
    var bar = function() {
        return foo.apply(obj, arguments);
    }
    var b = bar(3);
    console.log(b); //  5
    

    另一種表達這種模式的方法是創建一個可復用的幫助函數:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    
    function bind(fn, obj){
        return function(){
            return fn.apply(obj, arguments);
        };
    }
    
    var obj = { a:2};
    var bar = bind(foo, obj);
    var b = bar(3);
    console.log(b); // 5
    

    由於 硬綁定 是一個如此常用的模式,它已作為ES5的內建工具提供,即前文提到的Function.prototype.bind:

    function foo(something){
        console.log(this.a, something);
        return this.a + something;
    }
    var obj = { a:2};
    var bar = foo.bind(obj);
    var b = bar();
    cobsole.log(b); // 5
    
    

    bind(..)返回一個硬編碼的新函數,它使用你指定的this環境來調用原本的函數。

    注意: 在ES6中,bind(..)生成的硬綁定函數有一個名為.name的屬性,它源自於原始的 目標函數(target function)。舉例來說:bar = foo.bind(..)應該會有一個bar.name屬性,它的值為”bound foo”,這個值應當會显示在調用棧軌跡的函數調用名稱中。

    3.4new 綁定

    第四種也是最後一種this綁定規則

    當在函數前面被加入new調用時,也就是構造器調用時,下面這些事情會自動完成:

    • 一個全新的對象會憑空創建(就是被構建)
    • 這個新構建的對象會被接入原形鏈([[Prototype]]-linked)
    • 這個新構建的對象被設置為函數調用的this綁定
    • 除非函數返回一個它自己的其他 對象,這個被new調用的函數將 自動 返回這個新構建的對象。

    考慮這段代碼:

    function foo(a){
        console.log(this.a);
    }
    var bar = new foo(2);
    console.log(bar.a); // 2
    

    通過在前面使用new來調用foo(..),我們構建了一個新的對象並這個新對象作為foo(..)調用的this。 new是函數調用可以綁定this的最後一種方式,我們稱之為 new綁定(new binding)。

    3.5 優先級

    • new綁定
    • 显示綁定
    • 隱式綁定
    • 默認綁定(嚴格模式下會綁定到undefined)

    4. 箭頭函數

    箭頭函數並非使用function關鍵字進行定義,而是通過所謂的“大箭頭”操作符:=>,所以不會使用上面所講解的this四種標準規範,箭頭函數從封閉它的(function或global)作用域採用this綁定,即箭頭函數會繼承自外層函數調用的this綁定。

    執行 fruit.call(apple)時,箭頭函數this已被綁定,無法再次被修改。

    function fruit(){
        return () => {
            console.log(this.name);
        }
    }
    var apple = {
        name: '蘋果'
    }
    var banana = {
        name: '香蕉'
    }
    var fruitCall = fruit.call(apple);
    fruitCall.call(banana); // 蘋果
    

    5. 小結

    this是JavaScript的一個關鍵字,this不是編寫時綁定,而是運行時綁定。它依賴於函數調用的上下文條件。this綁定和函數聲明的位置無關,反而和函數被調用的方式有關。為執行中的函數判定this綁定需要找到這個函數的直接調用點。找到之後,4種規則將會以 這個 優先順序施用於調用點:

    • 被new調用?使用新構建的對象。
    • 被call或apply(或 bind)調用?使用指定的對象。
    • 被持有調用的環境對象調用?使用那個環境對象。
    • 默認:strict mode下是undefined,否則就是全局對

    與這4種綁定規則不同,ES6的箭頭方法使用詞法作用域來決定this綁定,這意味着它們採用封閉他們的函數調用作為this綁定(無論它是什麼)。它們實質上是ES6之前的self = this代碼的語法替代品。

    參考文章:

    深入理解JavScript中的this

    詳解JavaScript中的this

    你不懂this:豁然開朗

    你不懂this:this是什麼?

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 大摩:特斯拉Model 3自駕系統車禍降低90%

    大摩:特斯拉Model 3自駕系統車禍降低90%

    電動車大廠特斯拉(Tesla Inc.)要價35,000美元的平價車種「Model 3」預計2017年稍晚就能開賣,摩根士丹利(通稱大摩)認為,這款電動車的安全度會是一般車輛的10倍之多,發生死亡車禍的機率有望比其他車種低90%。

    根據網友最近在YouTube貼出影片,自駕系統「Autopilot」能提前好幾步預測到車禍。()

    MarketWatch、Business Insider等外電報導,大摩分析師Adam Jonas 23日發表研究報告指出,特斯拉為每台車安裝超級電腦後,車子安全性提升至其他車輛兩倍已經不夠看,他相信Model 3的安全度會是其他車輛的十倍之多,這會讓死亡車禍的發生機會降低90%。

    Jonas認為,缺少特斯拉駕車輔助科技的二手車價值將因而猛掉,未來甚至會被禁止上路。特斯拉蒐集資料的能力超群,還能將先進的安全輔助技術應用到電動車,還未推出類似科技的傳統車廠,競爭力堪虞。

    假如Model 3大獲成功、數百萬輛擁有自駕功能的車輛上路,那麼對行車安全的統計資料應有影響,這會凸顯其科技的優異程度,並迫使主管機關下令要求所有車輛都必須配備類似的系統。

    特斯拉23日終場下跌0.09%、收254.78美元;年初迄今已大漲19.23%。

    不過,最近有人仔細挖掘特斯拉向美國證管會(SEC)呈交的最新10-K報告,發現該公司已在內文悄悄坦承,Model 3 Beta版的原型車,至今尚無蹤影。

    美國權威汽車雜誌《Car and Driver》記者Anton Wahlman 3月2日報導(),特斯拉在3月1日發布的10-K報告中表示,已在測試Model 3的設計和製程時開發出多種版本,可作為Model 3 Beta版原型車的候選選項;在董事會選定要用哪一款作為Beta版的原型車之後,特斯拉下一階段的工作里程碑就能順利達陣。

    Wahlman認為,這意味著特斯拉在該份公告涵蓋的期間內(截至2016年12月31日為止),仍舊還未完成Model 3 Beta版的原型車。不過,這份文件是在2017年3月1日發布,這或許也代表至3月初為止,董事會還未對要用哪款原型車拍板定案。

      (本文內容由授權使用。圖片出處:Public Domain)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 擴電動車版圖,鴻海投資中國鋰電池廠

    擴電動車版圖,鴻海投資中國鋰電池廠

    鴻海自2014開始將旗下事業版圖擴大至電動車領域,3月29日公告於深圳的子公司富泰華工業以44.7億新台幣買下中國寧德時代新能源1.19%之股權,共擁有7,666,525股。

    母公司為鋰電池製造商新能源科技(ATL),寧德時代(CATL)主要研發生產電池芯、電池管理系統和動力電池系統,產品應用於電動車及儲能領域。

    鴻海董事長郭台銘事業瞄準電動車市場,繼2015年旗下富士康同騰訊及和諧汽車,三方合資成立和諧富騰以生產智慧電動車之後,和諧富騰於2016又投資成立初創公司Future Mobility Corporation(FMC),瞄準高階智慧電動車。

    FMC於2017年1月宣布將斥資116億元人民幣,於南京建高端智能電動車廠,第一期工程預計2019年可以完成。關於此次寧德時代的投資,董事長郭台銘表示為長期投資。

    (首圖來源:寧德時代)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 工研院高速充電鋁電池獲愛迪生獎,未來望應用電動車

    工研院高速充電鋁電池獲愛迪生獎,未來望應用電動車

    台灣研發於國際發光!擁有「創新界奧斯卡獎」美譽的愛迪生獎(Edison Awards)於21日美國紐約公布得獎名單,工研院在經濟部能源局的支持下,以「可高速充放電鋁電池」贏得評審團青睞,勇奪「能源與永續」類的銀牌,這次獲獎讓台灣的創意與研發能力持續在國際舞台上大放光芒,也突顯工研院的技術創新領先國際。

    愛迪生獎於1987 年設立,每年表彰全球創新產品與服務,紀念發明家愛迪生追求創意與卓越的精神,強調研發過程中的合作、試作、設計到產品應用開發,著重技術創新、差異化、商品化及影響力。歷屆獲獎者有iPad、3M 分子檢測系統、波音787 Dreamliner 等,今年入圍決選的國際大廠與研發機構包括:陶氏化學、MIT Media Lab、3M、美國國防部高等研究計劃署(DARPA)、Nokia、HP、默克藥廠等。

    愛迪生獎資深遴選委員Steve Herring 在頒獎現場表示:「我們很榮幸2017 年愛迪生獎有工研院參賽,他們努力追求創新的精神正是我們想要表揚的。」愛迪生獎執行總監Frank Bonafilia 亦讚許工研院在電池技術上提供了前所未有的實質發展。

    工研院綠能與環境研究所所長胡耀祖表示:「根據工研院產經中心(IEK)分析,2015 年全球商業電池市場約有791 億美元的規模。鋁電池突破過去30 年的技術瓶頸,不但可快速充放電,材料安全更不會引起爆炸,還可結合現有製程,大幅提升效率及降低成本,短期可望取代鉛酸電池,未來能將此應用擴大至電動機車、輕型電動車等交通載具,以及做為備用電力與儲能裝置。」

    胡耀祖進一步指出:「鋁電池未來還可搭配再生能源,成為我國儲能的重要生力軍,開啟一個能源產業與應用的新時代。目前電池材料、組裝和終端應用等產業,都能切入未來鋁電池的廣大市場,可望帶動我國電池產業升級,迎接新能源產業商機。」

    「可高速充放電鋁電池」為工研院與美國史丹佛大學共同合作,以地球上蘊藏豐富的石墨和鋁為原料,成功開發出全球第一個可以穩定充放電的鋁電池,只要一分鐘便可完成充電,且重複充放電逾萬次,仍可維持高蓄電量。此外,鋁電池所使用的離子液體在室溫下是液態的鹽類,若遇到高溫短路或是受到外力破壞,也不會爆炸燃燒。自2015 年登上英國《Nature》雜誌開始,「可高速充放電鋁電池」接連拿下2016 年百大研發獎(R&D 100 Awards)及2017 年愛迪生獎銀牌,在國際上備受肯定。工研院目前已布局包括核心電極材料、電解質材料、電芯與充電器等台灣及多國專利,且陸續獲證中,建立我國發展鋁電池產業的堅實根基。

    (合作媒體:。圖片出處:TechNews)

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 台達電佈局電動車產品,拓歐美電動車市場

    台達電佈局電動車產品,拓歐美電動車市場

    台達電於4月28日舉行法說會,公佈2017年第一季財報合併營收489.25億元新台幣,季減14%,年增2.8%;毛利率27.2%,季減0.06個百分點,年增0.26個百分點;因管控得宜,第一季匯兌收益1.4億元;稅後淨利39.19億元,每股盈餘1.51元,低於前一季的1.91元,略高於去年同期的1.50元。

    台達電執行長鄭平表示,公司5月起進行組織調整,擴大在電動車相關產品佈局,目前公司已打入歐美電動車廠,提供包括車載充電器、動力馬達、DC-DC轉換器等電動車零組件;在中國大陸也打入合資車廠,雖然電動車領域營收短期內成長幅度不大,但仍看好電動車領域未來長期的布局效益。

    台達電宣布組織調整,自2日起,將以「電源及零組件」、「自動化」與「基礎設施」為新三大業務範疇,其中,電源及零組件業務包括電動車方案事業群(EVSBG)、嵌入式電源系統事業群(EPSBG)、商用電源事業群(MPBG)、零組件事業群(CPBG)、風扇暨熱傳導事業群(FMBG);自動化業務包括機電事業群(IABG)、樓宇自動化事業群(BABG);至於基礎設施業務則包括資通訊基礎設施事業群(ICTBG)、能源基礎設施事業群(EISBG)。以新三大業務範疇區分,第一季電源及零組件占營收比重為55%、自動化占比為11%,基礎設施則占31%。

    對於未來營運展望,台達電董事長海英俊表示,第二季看好IA、樓宇自動化、數據中心的營運動能;今年雖然有匯率變數,但強調公司營運不會受到影響,並將持續朝向高毛利產品發展,讓毛利率能維持目前水準或更好。

    (本文內容由授權使用)  

     

    本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 看了Java的Class的源碼,我自閉了

    看了Java的Class的源碼,我自閉了

    java源碼之Class

    ​ 源碼的重要性不言而喻,雖然枯燥,但是也有拍案叫絕。這是我的源碼系列第二彈,後續還會一直更新,歡迎交流。String源碼可以看我的Java源碼之String,如有不足,希望指正。

    1.class這個類是什麼

    Class的本質也是一個類,只不過它是將我們定義類的共同的部分進行抽象,比如我們常定義的類都含有構造方法,類變量,函數,而Class這個類就是來操作這些屬性和方法的。當然我們常定義的類包含的類型都可以通過Class間接的來操作。而類的類型包含一般的類,接口,枚舉類型,註解類型等等。這麼說可能有點太理論,我們看下面這個例子:

    我們將生活中的一類事物抽象為一個類的時候,往往是因為他們具有相同的共性和不同的個性。定義一個類的作用就是將相同的共性抽離出來。一般的類都包含屬性和方法(行為),下面我們定義水果和汽車這兩個大類:

    代碼如下:

    汽車類:

    class Car{
    
        // 定義屬性
        private String name;
        private String color;
    
        /**
         * 定義兩個構造方法
         */
        public Car(){
    
        }
    
        public Car(String name,String color){
            this.name = name;
            this.color = color;
        }
    
        /**
         * 定義兩個普通方法(行為)
         */
        public void use(){
            
        }
        
        public void run(){
            
        }
    
        /**
         * 屬性的get和set方法
         * @return
         */
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getColor() {
            return color;
        }
    
        public void setColor(String color) {
             this.color = color;
        }
    }
    
    
    

    水果類:

    class Fruit{
    
        // 定義屬性
        private String name;
        private int size;
    
        /**
         * 定義兩個構造方法
         */
        public Fruit(){
    
        }
    
        public Fruit(String name,int size){
            this.name = name;
            this.size =size;
        }
    
        /**
         * 定義兩個方法(行為)
         */
        public void use(){
            
        }
        
        public void doFruit(){
            
        }
    
        /**
         * 屬性的get和set方法
         * @return
         */
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getSize() {
            return size;
        }
    
        public void setSize(int size) {
            this.size = size;
        }
    }
    

    可以看到水果和汽車這兩個類都有共同的部分,也就是一個類共同的部分,那就是屬性和方法,而Class就是來操作我們定義類的屬性和方法。

    ​小試牛刀:通過Class這個類來獲取Fruit這個類中定義的方法;

    public static void main(String[] args) {
    
            Fruit fruit = new Fruit();
            Class fruitClass = fruit.getClass();
    
            Method[] fruitMethods = fruitClass.getMethods();
            System.out.println("方法個數:" + fruitMethods.length);
    
            for (Method method : fruitMethods) {
                //得到返回類型
                System.out.print("方法名稱和參數:" + method.getName() + "(");
                //取得某個方法對應的參數類型數組
                Class[] paramsType = method.getParameterTypes();
                for (Class paramType : paramsType) {
                    System.out.print(paramType.getTypeName() + " ");
                }
                System.out.print(")");
    
                Class returnType = method.getReturnType();
                System.out.println("返回類型:" + returnType.getTypeName());
            }
        }
    

    運行結果:

    方法個數:15
    方法名稱和參數:getName()返回類型:java.lang.String
    方法名稱和參數:setName(java.lang.String )返回類型:void
    方法名稱和參數:getSize()返回類型:int
    方法名稱和參數:setSize(int )返回類型:void
    方法名稱和參數:use()返回類型:void
    方法名稱和參數:doFruit()返回類型:void
    方法名稱和參數:wait()返回類型:void
    方法名稱和參數:wait(long int )返回類型:void
    方法名稱和參數:wait(long )返回類型:void
    方法名稱和參數:equals(java.lang.Object )返回類型:boolean
    方法名稱和參數:toString()返回類型:java.lang.String
    方法名稱和參數:hashCode()返回類型:int
    方法名稱和參數:getClass()返回類型:java.lang.Class
    方法名稱和參數:notify()返回類型:void
    方法名稱和參數:notifyAll()返回類型:void
    

    這裏可能有人疑惑了,Fruit類並沒有定義的方法為什麼會出現,如wait(),equals()方法等。這裏就有必要說一下java的繼承和反射機制。在繼承時,java規定每個類默認繼承Object這個類,上述這些並沒有在Fruit中定義的方法,都是Object中的方法,我們看一下Object這個類的源碼就會一清二楚:

     public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
    
     public final native void wait(long timeout) throws InterruptedException;
    
     public final void wait() throws InterruptedException {
            wait(0);
        }
    

    而Class類中的getMethods()方法默認會獲取父類中的公有方法,也就是public修飾的方法。所以Object中的公共方法也出現了。

    注: 要想獲得父類的所有方法(public、protected、default、private),可以使用apache commons包下的FieldUtils.getAllFields()可以獲取類和父類的所有(public、protected、default、private)屬性。

    是不是感覺非常的強大 ,當然,使用Class來獲取一些類的方法和屬性的核心思想就是利用了Java反射特性。萬物皆反射,可見反射的強大之處,至於反射的原理,期待我的下一個博客。

    2.常用方法的使用以及源碼分析

    2.1構造方法

    源碼如下:

     private Class(ClassLoader loader) {
            // Initialize final field for classLoader.  The initialization value of non-null
            // prevents future JIT optimizations from assuming this final field is null.
            classLoader = loader;
        }
    

    可以看到Class類只有一個構造函數,並且是私有的。也就是說不能通過new來創建這個類的實例。官方文檔的解釋:私有構造函數,僅Java虛擬機創建Class對象。我想可能就是為了安全,具體原因不是很了解。如果有了解的話,可以在評論區內共同的交流。

    Class是怎麼獲取一個實例的。

    那麼既然這個class構造器私有化,那我們該如何去構造一個class實例呢,一般採用下面三種方式:

    1.運用.class的方式來獲取Class實例。對於基本數據類型的封裝類,還可以採用.TYPE來獲取相對應的基本數據類型的Class實例,如下的示例。

     // 普通類獲取Class的實例。接口,枚舉,註解,都可以通過這樣的方式進行獲得Class實例
    Class fruitClass = Fruit.class;
    
    // 基本類型和封裝類型獲得Class實例的方式,兩者等效的
    Class intClass = int.class;
    Class intClass1 = Integer.TYPE;
    

    下面的表格兩邊等價:

    boolean.class Boolean.TYPE
    char.class Character.TYPE
    byte.class Byte.TYPE
    short.class Short.TYPE
    int.class Integer.TYPE
    long.class Long.TYPE
    float.class Float.TYPE
    double.class Double.TYPE
    void.class Void.TYPE

    但是這種方式有一個不足就是對於未知的類,或者說不可見的類是不能獲取到其Class對象的。

    2.利用對象.getClass()方法獲取該對象的Class實例;

    這是利用了Object提供的一個方法getClass() 來獲取當著實例的Class對象,這種方式是開發中用的最多的方式,同樣,它也不能獲取到未知的類,比如說某個接口的實現類的Class對象。

    Object類中的getClass()的源碼如下:

    public final native Class<?> getClass();
    

    源碼說明:

    可以看到,這是一個native方法(一個Native Method就是一個java調用非java代碼的接口),並且不允許子類重寫,所以理論上所有類型的實例都具有同一個 getClass 方法。

    使用:

     Fruit fruit = new Fruit();
     Class fruitClass = fruit.getClass();
    

    3.使用Class類的靜態方法forName(),用類的名字獲取一個Class實例(static Class forName(String className) ),這種方式靈活性最高,根據類的字符串全名即可獲取Class實例,可以動態加載類,框架設計經常用到;

    源碼如下:

        /*
         由於方法區 Class 類型信息由類加載器和類全限定名唯一確定,所以參數name必須是全限定名,
         參數說明   name:class名,initialize是否加載static塊,loader 類加載器
         */
        public static Class<?> forName(String name, boolean initialize,
                                       ClassLoader loader)
            throws ClassNotFoundException
        {
            Class<?> caller = null;
            
            // 1.進行安全檢查
            SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
               ....
                }
            }
            // 2.調用本地的方法
            return forName0(name, initialize, loader, caller);
        }
       
        // 3.核心的方法
        private static native Class<?> forName0(String name, boolean initialize,
                                                ClassLoader loader,
                                                Class<?> caller)
          throws ClassNotFoundException;
    
       /* 
        這個 forName是上述方法的重載,平時一般都使用這個 方法默認使用調用者的類加載器,將類的.class文件加載     到 jvm中
        這裏傳入的initialize為true,會去執行類中的static塊
        */
        public static Class<?> forName(String className)
                    throws ClassNotFoundException {
            Class<?> caller = Reflection.getCallerClass();
            return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
        }
    
    

    源碼說明已在註釋中說明,有些人會疑惑, static native Class<?> forName0()這個方法的實現。

    這就要說到java的不完美的地方了,Java的不足除了體現在運行速度上要比傳統的C++慢許多之外,Java無法直接訪問到操作系統底層(如系統硬件等),為此Java使用native方法來擴展Java程序的功能。有關native的方法請移步這裏。

    基本使用:

     Class fruitClass = Class.forName("cn.chen.test.util.lang.Fruit");
    

    : 這種方式必須使用類的全限定名,,這是因為由於方法區 Class 類型信息由類加載器和類全限定名唯一確定,否則會拋出ClassNotFoundException的異常。

    2.2一般方法以及源碼分析:

    Class類的一般的方法總共有六十多種,其實看到這麼多方法咱也不要慫,這裏面還有很多重載的方法,根據二八原則,我們平時用的也就那麼幾個方法,所以這裏只對以下幾個方法的使用和實現進行交流,其他的方法可以移步Java官方文檔:

    2.2.1 獲得類的構造方法

    這個方法主要是用來了解一個類的構造方法有哪些,包含那些參數,特別是在單例的模式下。一般包含的方法如下:

    • public Constructor[] getConstructors() :獲取類對象的所有可見的構造函數

    • public Constructor[] getDeclaredConstructors():獲取類對象的所有的構造函數

    • public Constructor getConstructor(Class… parameterTypes): 獲取指定的可見的構造函數,參數為:指定構造函數的參數類型數組,如果該構造函數不可見或不存在,會拋出 NoSuchMethodException 異常

    • public Constructor getDeclaredConstructor(Class… parameterTypes) :獲取指定的構造函數,參數為:指定構造函數的參數類型數組,無論構造函數可見性如何,均可獲取

    基本使用:

    Constructor[] constructors = fruitClass.getConstructors();
     for (Constructor constructor : constructors) {
                System.out.println("獲得共有的構造方法:"+constructor);
            }
    

    輸出結果:

    獲得共有的構造方法:public cn.chen.test.util.lang.Fruit()
    獲得共有的構造方法:public cn.chen.test.util.lang.Fruit(java.lang.String,int)
    

    可以看到我們前面定義的來個構造方法,都被打印出來了。注意getConstructors()只能獲得被public修飾的構造方法,如果要獲得被(protected,default,private)修飾的構造方法,就要使用的getDeclaredConstructors()這個方法了。接下來,修改Fruit中的一個構造方法為private:

     private  Fruit(String name,int size){
            this.name = name;
            this.size =size;
        }
    

    使用getConstructors()和getDeclaredConstructors()着兩個方法進行測試:

           Class fruitClass = Fruit.class;       
           Constructor[] constructors = fruitClass.getConstructors();
           Constructor[] constructors1 = fruitClass.getDeclaredConstructors();
    
            for (Constructor constructor : constructors) {
                System.out.println("獲得共有的構造方法:"+constructor);
            }
    
            System.out.println("=================================================");
            for (Constructor constructor : constructors1) {
                System.out.println("獲得所有的構造方法:"+constructor);
            }
    

    輸出結果:

    獲得共有的構造方法:public cn.chen.test.util.lang.Fruit()
    ===================分隔線=============================
    獲得所有的構造方法:public cn.chen.test.util.lang.Fruit()
    獲得所有的構造方法:private cn.chen.test.util.lang.Fruit(java.lang.String,int)
    

    可以看到兩者的區別。所以,反射在一定程度上破壞了java的封裝特性。畢竟人無完人,語言亦是一樣。

    getConstructors()的源碼分析:

    public Constructor<?>[] getConstructors() throws SecurityException {
              
            // 1.檢查是否允許訪問。如果訪問被拒絕,則拋出SecurityException。
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
            return copyConstructors(privateGetDeclaredConstructors(true));
        }
        
     private static <U> Constructor<U>[] copyConstructors(Constructor<U>[] arg) {
          // 2.使用克隆,得到當前類的所有構造函數   
          Constructor<U>[] out = arg.clone();
         // 3.使用ReflectionFactory構造一個對象,也是不使用構造方法構造對象的一種方式。
            ReflectionFactory fact = getReflectionFactory();
         // 4.遍歷,將構造函數進行拷貝返回,注意在調用fact.copyConstructor(out[i])這個方法的時候,還會進行安全檢查,用的就是下面的LangReflectAccess() 這個方法。
            for (int i = 0; i < out.length; i++) {
                out[i] = fact.copyConstructor(out[i]);
            }
            return out;
        }
    
    
    
     private static LangReflectAccess langReflectAccess() {
            if (langReflectAccess == null) {
                Modifier.isPublic(1);
            }
    
            return langReflectAccess;
        } 
    
    

    通過打斷點調試,可以看到下面的信息:

    代碼的調用邏輯在註釋里已進行說明。

    2.2.2 獲得屬性

    主要獲取類的屬性字段,了解這個類聲明了那些字段。

    一般有四個方法:

    • public Field[] getFields():獲取所有可見的字段信息,Field數組為類中聲明的每一個字段保存一個Field 實例
    • public Field[] getDeclaredFields():獲取所有的字段信息
    • public Field getField(String name) :通過字段名稱獲取字符信息,該字段必須可見,否則拋出異常
    • public Field getDeclaredField(String name) :通過字段名稱獲取可見的字符信息

    基本使用:

    首先我們在Fruit的類中加入一個public修飾的屬性:

        public double weight;
    
    Class fruitClass = Fruit.class; 
    Field[] field2 = fruitClass.getFields();
            for (Field field : field2) {
                System.out.println("定義的公有屬性:"+field);
            }
    
            Field[] fields = fruitClass.getDeclaredFields();
            for (Field field : fields) {
                System.out.println("定義的所有屬性:"+field);
            }
    

    輸出結果:

    定義的公有屬性:public double cn.chen.test.util.lang.Fruit.weight
    ========================分隔線============================
    定義的所有屬性:private java.lang.String cn.chen.test.util.lang.Fruit.name
    定義的所有屬性:private int cn.chen.test.util.lang.Fruit.size
    定義的所有屬性:public double cn.chen.test.util.lang.Fruit.weight
    

    源碼分析,就以getFileds()這個方法為例,涉及以下幾個方法:

    public Field[] getFields() throws SecurityException {
            // 1.檢查是否允許訪問。如果訪問被拒絕,則拋出SecurityException。
            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
            return copyFields(privateGetPublicFields(null));
        }
     
     private static Field[] copyFields(Field[] arg) {
             // 2. 聲明一個Filed的數組,用來存儲類的字段 
            Field[] out = new Field[arg.length];
            //  3.使用ReflectionFactory構造一個對象,也是不使用構造方法構造對象的一種方式。
            ReflectionFactory fact = getReflectionFactory();
           // 4.遍歷,將字段複製后返回。
            for (int i = 0; i < arg.length; i++) {
                out[i] = fact.copyField(arg[i]);
            }
            return out;
        }
        
     public Field copyField(Field var1) {
            return langReflectAccess().copyField(var1);
        }
     
    // 再次檢查屬性的訪問權限
      private static LangReflectAccess langReflectAccess() {
            if (langReflectAccess == null) {
                Modifier.isPublic(1);
            }
    
            return langReflectAccess;
        }
    

    2.2.3 獲得一般方法

    就是獲取一個類中的方法,一般有以下幾個方法:

    • public Method[] getMethods(): 獲取所有可見的方法

    • public Method[] getDeclaredMethods() :獲取所有的方法,無論是否可見

    • public Method getMethod(String name, Class… parameterTypes)

      參數說明:

    1. 通過方法名稱、參數類型獲取方法
    2. 如果你想訪問的方法不可見,會拋出異常
    3. 如果你想訪問的方法沒有參數,傳遞 null作為參數類型數組,或者不傳值)
    • public Method getDeclaredMethod(String name, Class… parameterTypes)
    1. 通過方法名稱、參數類型獲取方法
    2. 如果你想訪問的方法沒有參數,傳遞 null作為參數類型數組,或者不傳值)

    基本使用:

    //在fruit中定義一個這樣的方法
     private  void eat(String describe){
            System.out.println("通過getMethod()方法調用了eat()方法:  "+describe);
        }
    

    調用這個方法:

            Class fruitClass = Fruit.class;
            Method method = fruitClass.getDeclaredMethod("eat",String.class);
            method.setAccessible(true);
            method.invoke(fruitClass.newInstance(),"我是該方法的參數值");
    

    輸出結果:

      通過getMethod()方法調用了eat()方法:我是該方法的參數值
    

    分析getDeclaredMethod()涉及的源碼:

    public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
            throws NoSuchMethodException, SecurityException {
            // 1.檢查方法的修飾符
            checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
            // 2.searchMethods()方法的第一個參數確定這個方法是不是私有方法,第二個參數我們定義的方法名,第三個參數就是傳入的方法的參數類型
            Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
            if (method == null) {
                throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
            }
            return method;
        }
    
    // 這個方法就是通過傳入的方法名找到我們定義的方法,然後使用了Method的copy()方法返回一個Method的實例,我們通過操作mehtod這個實例就可以操作我們定義的方法。
     private static Method searchMethods(Method[] methods,
                                            String name,
                                            Class<?>[] parameterTypes)
        {
            Method res = null;
            String internedName = name.intern();
            for (int i = 0; i < methods.length; i++) {
                Method m = methods[i];
                if (m.getName() == internedName
                    && arrayContentsEq(parameterTypes, m.getParameterTypes())
                    && (res == null
                        || res.getReturnType().isAssignableFrom(m.getReturnType())))
                    res = m;
            }
    
            return (res == null ? res : getReflectionFactory().copyMethod(res));
        }
    
     public Method copyMethod(Method var1) {
            return langReflectAccess().copyMethod(var1);
        }
    
     
    // 檢查屬性的訪問權限
      private static LangReflectAccess langReflectAccess() {
            if (langReflectAccess == null) {
                Modifier.isPublic(1);
            }
    
            return langReflectAccess;
        }
    

    2.2.4 判斷類的類型的方法

    這類型的方法顧名思義,就是來判斷這個類是什麼類型,是接口,註解,枚舉,還是一般的類等等。部分方法如下錶

    boolean isAnnotation()判斷是不是註解
    boolean isArray() 判斷是否為數組
    boolean isEnum()判斷是否為枚舉類型
    boolean isInterface() 是否為接口類型
    boolean isMemberClass()當且僅當基礎類是成員類時,返回“true”
    boolean isPrimitive()確定指定的“類”對象是否表示原始類型。
    boolean isSynthetic()如果這個類是合成類,則返回’ true ‘;否則返回“false”。

    基本用法:

    // 定義一個接口:
    interface  Animal{
        public void run();
    }
    

    判斷是不是一個接口:

    Class AnimalClass = Animal.class;
     boolean flag = AnimalClass.isInterface();
     System.out.println(flag);
    

    輸出結果:

    true
    

    源碼分析isInterface():

     public native boolean isInterface();
    

    這是一個native方法,大家都知道native方法是非Java語言實現的代碼,供Java程序調用的,因為Java程序是運行在JVM虛擬機上面的,要想訪問到比較底層的與操作系統相關的就沒辦法了,只能由靠近操作系統的語言來實現。

    2.2.5 toString()方法

    將對象轉換為字符串。字符串表示形式是字符串“類”或“接口”,後跟一個空格,然後是該類的全限定名。

    基本使用:

    // 這是前面定義的兩個類Fruit和Car,Car是一個接口
     Class fruitClass = Fruit.class;
     Class AnimalClass = Animal.class;
     System.out.println(AnimalClass.toString());
     System.out.println(fruitClass.toString());
    

    輸出結果:

    // 格式  字符串“類”或“接口”,後跟一個空格,然後是該類的全限定名
    interface cn.chen.test.util.lang.Animal
    class cn.chen.test.util.lang.Fruit
    

    源碼如下:

     public String toString() {
           // 先是判斷是接口或者類,然後調用getName輸出類的全限定名
            return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
                + getName();
        }
    
      public native boolean isInterface();
      public native boolean isPrimitive();
    

    追本溯源,方能闊步前行。

    參考資料

    ​ https://blog.csdn.net/x_panda/article/details/17120479

    ​ https://juejin.im/post/5d4450fbe51d4561ce5a1be1

    ​ JavaSE的官方文檔

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 005.OpenShift訪問控制-權限-角色

    005.OpenShift訪問控制-權限-角色

    一 Kubetcl namespace

    1.1 namespace描述


    Kubernetes namespace提供了將一組相關資源組合在一起的機制。在Red Hat OpenShift容器平台中,project是一個帶有附加註釋的Kubernetes namespace。

    namespace提供以下特性:

    1. 命名資源,以避免基本的命名衝突;
    2. 將管理權限授予受信任的用戶;
    3. 限制用戶資源消耗的能力;
    4. 用戶和用戶組隔離。

    1.2 project


    project提供了一種機制,通過這種機制可以管理普通用戶對資源的訪問。project允許一組用戶獨立於其他組組織和管理其內容,必須允許用戶訪問項目。如果允許創建項目,用戶將自動訪問自己的項目。

    項目可以有單獨的name、display name和description。

    name是項目的唯一標識符,在使用CLI工具或API時都是基於name,name的最大長度為63個字符。

    display name是項目在web控制台中显示的方式(默認為name)。

    description是項目的更詳細描述,並且在web控制台中也可見。

    以下組件適用於項目:

    • Object:pod、service、rc等;
    • Policies:決定用戶可以或不能對對象執行哪些操作的規則;
    • Constraints:可以限制的每種對象的配額。

    1.3 cluster管理


    集群管理員可以創建項目並將項目的管理權限委託給任何用戶。在OpenShift容器平台中,項目用於對相關對象進行分組和隔離。

    管理員可以讓用戶訪問某些項目,允許他們創建自己的項目,並在單個項目中賦予他們管理權限。

    管理員可以將角色應用於允許或限制其創建項目能力的用戶和組,同時可以在用戶初始登錄之前分配角色。

    限制項目創建:從通過身份驗證的用戶和組中刪除self-provisioning集群角色,將拒絕任何新項目的權限。

    [root@master ~]$ oc adm policy remove-cluster-role-from-group \

    self-provisioner \

    system:authenticated \

    system:authenticated:oauth

    授予項目創建:項目創建授予具有self-供應者角色和self-provisione集群角色綁定的用戶。默認情況下,所有經過身份驗證的用戶都可以使用這些角色。

    [root@master ~]$ oc adm policy add-cluster-role-to-group \

    self-provisioner \

    system:authenticated \

    system:authenticated:oauth

    1.4 創建project


    如果項目創建權限被授予用戶,則可以使用oc命令創建project。

    [root@master ~]$ oc new-project demoproject \

    –description=”Demonstrate project creation” \

    –display-name=”demo_project”

    二 OpenShift角色

    2.1 角色概述


    role具有不同級別的訪問和策略,包括集群和本地策略。user和group可以同時與多個role關聯。運行oc description命令查看角色及其綁定的詳細信息。

    在集群策略中具有cluster-admin缺省角色的用戶可以查看集群策略和所有本地策略。在給定的本地策略中具有admin缺省角色的用戶可以基於per-project查看策略。

    可通過以下命令查看當前的集群綁定集,其中显示綁定到不同角色的用戶和組。

    [root@demo ~]# oc describe clusterPolicyBindings :default

    2.2 查看本地policy


    儘管本地角色列表及其關聯的規則集在本地策略中是不可查看的,但是所有缺省角色仍然適用,並且可以添加到用戶或組中,cluster-admin缺省角色除外。但是,本地綁定是可見的。

    可通過以下命令查看當前的本地綁定,其中显示綁定到不同角色的用戶和組。

    [root@demo ~]# oc describe policyBindings :default

    提示:默認情況下,在本地策略中,只會列出admin角色的綁定。但是,如果將其他默認角色添加到本地策略中的用戶和組,也會列出它們。

    2.3 管理role綁定


    向用戶或組添加或綁定角色,從而實現向用戶或組提供角色授予的相關訪問權限。可以使用oc adm policy命令在用戶和組之間添加和刪除角色。

    當使用以下操作管理本地策略的用戶和組角色時,可以使用-n選項指定項目。如果沒有指定,則使用當前項目。

    常見管理本地策略操作:





























    命令 描述
    oc adm policy who-can verb resource 設置哪些用戶可以對資源執行操作
    oc adm policy add-role-to-user role username 將指定角色綁定到指定用戶
    oc adm policy remove-role-from-user role username 從指定用戶中移除給定角色
    oc adm policy remove-user username 刪除指定的用戶及其所有角色
    oc adm policy add-role-to-group role groupname 將指定的角色綁定到指定的組
    oc adm policy remove-role-fromgroup role groupname 從指定組中移除給定角色
    oc adm policy remove-group groupname 刪除指定的組及其所有角色


    還可以使用如下所示的的操作管理cluster policy的role binding,這類命令不需要-n選項,因為cluster policy不在namespace級別上操作。

    常見管理cluster policy操作:




















    命令 描述
    oc adm policy add-cluster-role-to-user role username 將集群中所有項目的指定角色綁定到指定用戶
    oc adm policy remove-cluster-role-from-user role username 為集群中的所有項目從指定用戶中刪除指定角色
    oc adm policy add-cluster-role-togroup role groupname 為集群中的所有項目將指定的角色綁定到指定的組
    oc adm policy remove-cluster-role-from-group role groupname 從集群中所有項目的指定組中移除給定角色


    提示:oc policy命令應用於當前項目,而oc adm policy命令應用於集群範圍的操作。

    示例:在example項目中為developer用戶提供admin角色。

    [root@demo ~]# oc adm policy add-role-to-user admin developer -n example

    [root@demo ~]# oc describe policybindings :default -n example #檢查綁定

    三 安全上下文約束(SCCS)

    3.1 SCCS概述


    OpenShift提供安全上下文約束(SCCS),它控制pod可以執行的操作和它可以訪問的資源。默認情況下,任何容器的執行都只授予受限制的SCC定義的功能。

    SCCS相關命令:

      1 [user@demo ~]$ oc get scc			                        #列出可用的SCC
      2 [user@demo ~]$ oc describe scc scc_name		                #現實特定SCC詳細信息
      3 [user@demo ~]$ oc adm policy add-scc-to-user scc_name user_name
      4 [user@demo ~]$ oc adm policy add-scc-to-group scc_name group_name	#要授予用戶或組特定的SCC
      5 [user@demo ~]$ oc adm policy remove-scc-from-user scc_name user_name
      6 [user@demo ~]$ oc adm policy remove-scc-from-group scc_name group_name	#從特定的SCC中刪除用戶或組


    四 服務賬戶

    4.1 服務賬戶


    service account提供了一種靈活的方法來控制API訪問,而無需共享常規用戶的憑據。如果應用程序需要訪問受限制的SCC未授予的功能,可創建一個新的、特定的service account並將其添加到適當的SCC中。

    例如,在缺省情況下,OpenShift不支持部署需要提升特權的應用程序。若有此需求,可創建一個service account,修改dc,然後添加service account至SCC。

    示例:將anyuid配置為在容器中作為root用戶運行。

    [user@demo ~]$ oc create serviceaccount useroot #創建一個名為useroot的新服務帳戶

    [user@demo ~]$ oc patch dc/demo-app \

    –patch ‘{“spec”:{“template”:{“spec”:{“serviceAccountName”: “useroot”}}}}’ #修改應用程序的DC

    [user@demo ~]$ oc adm policy add-scc-to-user anyuid -z useroot #將useroot服務帳戶添加到anyuid SCC中,作為容器中的根用戶運行

    4.2 Web管理user成員


    OCP平台的默認配置是,在用戶首次登錄成功時,自動創建該用戶對象。

    要管理允許訪問項目的用戶,請以項目管理員或集群管理員的身份登錄到web控制台,並選擇要管理的項目。在左側窗格中,單擊Resources——>membership進入項目member頁面。

    在Users列中,在突出显示的文本框中輸入用戶名。在“添加另一個角色”列中,從用戶所在行的列表中選擇一個角色,然後單擊“添加”。

    4.3 Cli管理user成員


    CLI中如果自動創建對象功能被關閉,集群管理員可通過如下方式創建新用戶:

    [root@master ~]$ oc create user demo-user

    同時還需要在身份認證軟件中創建用戶,如為HTPasswdIdentityProvider才用戶命令如下:

    [root@master ~]$ htpasswd /etc/origin/openshift-passwd demo-user

    要向用戶添加項目角色,首先使用oc project命令輸入項目,然後使用oc policy add-role-to-user命令:

    [root@master ~]$ oc policy add-role-to-user edit demo-user

    要從用戶中刪除項目角色,使用oc policy remove-role-from-user命令:

    [root@master ~]$ oc policy remove-role-from-user edit demo-user

    並不是所有OpenShift角色都由項目限定範圍。要分配這些規則,請使用oc adm policy command命令。

    [root@master ~]$ oc adm policy add-cluster-role-to-user cluster-admin admin

    4.4 身份驗證和授權


    身份驗證層標識與對OpenShift容器平台API的請求相關聯的用戶,然後授權層使用關於請求用戶的身份信息來確定是否應該允許該請求。

    • user和group


    OCP容器平台中的用戶是一個可以向OpenShift API發出請求的實體。通常,這表示與OpenShift交互的develop或administrator的帳戶。

    可以將用戶分配給一個或多個組,每個組表示一組特定的角色(或權限)。當需要通過管理授權策略給多個客戶授權時候,group會比較合適。例如允許訪問項目中的對象,而不是單獨授予用戶。

    • Authentication Tokens


    API調用必須使用訪問令牌或X.509證書進行身份驗證,會話token表示用戶,並且是短期的,默認情況下在24小時內到期。

    可以通過運行oc whoami命令來驗證經過身份驗證的用戶。

    [root@master ~]$ oc login -u demo-user

    [root@master ~]$ oc whoami

    demo-user

    4.5 身份驗證類型


    本環境中,身份驗證由HTPasswdIdentityProvider模塊提供,該模塊根據使用htpasswd命令生成的文件驗證用戶名和密碼。

    OpenShift容器平台支持的其他認證類型包括:

    • Basic Authentication (Remote)


    一種通用的後端集成機制,允許用戶使用針對遠程標識提供者驗證的憑據登錄到OpenShift容器平台。用戶將他們的用戶名和密碼發送到OpenShift容器平台,OpenShift平台通過到服務器的請求驗證這些憑據,並將憑據作為基本的Auth頭傳遞。這要求用戶在登錄過程中向OpenShift容器平台輸入他們的憑據。

    • Request Header Authentication


    用戶使用請求頭值(如X-RemoteUser)登錄到OpenShift容器平台。它通常與身份驗證代理結合使用,身份驗證代理對用戶進行身份驗證,然後通過請求頭值為OpenShift容器平台提供用戶標識。

    • Keystone Authentication


    Keystone是一個OpenStack項目,提供標識、令牌、目錄和策略服務。OpenShift容器平台與Keystone集成,通過配置OpenStack Keystone v3服務器將用戶存儲在內部數據庫中,從而支持共享身份驗證。這種配置允許用戶使用Keystone憑證登錄OpenShift容器平台。

    • LDAP Authentication


    用戶使用他們的LDAP憑證登錄到OpenShift容器平台。在身份驗證期間,LDAP目錄將搜索與提供的用戶名匹配的條目。如果找到匹配項,則嘗試使用條目的專有名稱(DN)和提供的密碼進行簡單綁定。

    • GitHub Authentication


    GitHub使用OAuth,它允許與OpenShift容器平台集成使用OAuth身份驗證來促進令牌交換流。這允許用戶使用他們的GitHub憑證登錄到OpenShift容器平台。為了防止使用GitHub用戶id的未授權用戶登錄到OpenShift容器平台集群,可以將訪問權限限制在特定的GitHub組織中。

    五 管理項目及賬戶

    5.1 前置準備


    準備完整的OpenShift集群,參考《003.OpenShift網絡》2.1。

    5.2 本練習準備


    [student@workstation ~]$ lab secure-resources setup

    5.3 創建htpasswd賬戶

      1 [kiosk@foundation0 ~]$ ssh root@master
      2 [root@master ~]# htpasswd -b /etc/origin/master/htpasswd user1 redhat
      3 [root@master ~]# htpasswd -b /etc/origin/master/htpasswd user2 redhat
      4 #添加基於htpasswd形式的user1和user2,密碼都為redhat。


    5.4 設置策略

      1 [student@workstation ~]$ oc login -u admin -p redhat https://master.lab.example.com	#使用管理員登錄
      2 [student@workstation ~]$ oc adm policy remove-cluster-role-from-group \
      3 self-provisioner system:authenticated:oauth
      4 #刪除所有賦予普通創建項目的功能,該命令可參考本環境如下目錄中的命令。
      5 [student@workstation ~]$ cat /home/student/DO280/labs/secure-resources/configure-policy.sh
      6 #!/bin/bash
      7 oc adm policy remove-cluster-role-from-group \
      8     self-provisioner system:authenticated system:authenticated:oauth


    5.5 驗證策略

      1 [student@workstation ~]$ oc login -u user1 -p redhat https://master.lab.example.com	#使用普通用戶user1登錄
      2 [student@workstation ~]$ oc new-project test					#測試創建project
      3 Error from server (Forbidden): You may not request a new project via this API.


    5.6 創建項目

      1 [student@workstation ~]$ oc login -u admin -p redhat https://master.lab.example.com	#使用集群管理員登錄
      2 [student@workstation ~]$ oc new-project project-user1				#創建兩個項目
      3 [student@workstation ~]$ oc new-project project-user2


    5.7 將項目與user關聯

      1 #選擇項目1
      2 Now using project "project-user1" on server "https://master.lab.example.com:443".
      3 [student@workstation ~]$ oc policy add-role-to-user admin user1		#將user1添加為項目1的管理員
      4 role "admin" added: "user1"
      5 [student@workstation ~]$ oc policy add-role-to-user edit user2		#將user2添加為項目1的開發員
      6 role "edit" added: "user2"
      7 
      8 [student@workstation ~]$ oc project project-user2			        #選擇項目2
      9 Now using project "project-user2" on server "https://master.lab.example.com:443".
     10 [student@workstation ~]$ oc policy add-role-to-user edit user2		#將user2添加為項目2的開發員
     11 role "edit" added: "user2"


    5.8 驗證訪問

      1 [student@workstation ~]$ oc login -u user1 -p redhat https://master.lab.example.com	#使用user1登錄
      2 [student@workstation ~]$ oc project project-user1					#驗證項目1的訪問
      3 Already on project "project-user1" on server "https://master.lab.example.com:443".
      4 [student@workstation ~]$ oc project project-user2					#驗證項目2的訪問
      5 error: You are not a member of project "project-user2".
      6 You have one project on this server: project-user1
      7 
      8 [student@workstation ~]$ oc login -u user2 -p redhat https://master.lab.example.com	#使用user2登錄
      9 [student@workstation ~]$ oc project project-user1
     10 Already on project "project-user1" on server "https://master.lab.example.com:443".	#驗證項目1的訪問
     11 [student@workstation ~]$ oc project project-user2
     12 Now using project "project-user2" on server "https://master.lab.example.com:443".	#驗證項目2的訪問


    5.9 部署特權應用

      1 [student@workstation ~]$ oc login -u user2 -p redhat https://master.lab.example.com
      2 [student@workstation ~]$ oc project project-user1
      3 Now using project "project-user1" on server "https://master.lab.example.com:443".
      4 [student@workstation ~]$ oc new-app --name=nginx --docker-image=registry.lab.example.com/nginx:latest
      5 #使用在項目1上不具備admin權限的用戶user2登錄,並部署應用,會出現如下提示:





    5.10 驗證部署

      1 [student@workstation ~]$ oc get pods




    結論:由上可知,部署失敗是因為容器映像需要root用戶,pod以CrashLoopBackOff或錯誤狀態結束。

    5.11 故障排除


    若要解決此故障需要減少特定項目的安全限制。

    要使用特權訪問運行容器,可創建一個允許pod使用操作系統普通用戶運行的service account。

    如下部分需要具有項目管理員特權的用戶執行,而另一些操作需要具有集群管理員特權的用戶執行。

    本環境中,相關操作命令可以從/home/student/DO280/labs/secure-resources文件夾中的configure-sc.sh腳本運行或複製。

      1 [student@workstation ~]$ oc login -u user1 -p redhat https://master.lab.example.com	#使用項目1的admin賬戶登錄 
      2 [student@workstation ~]$ oc create serviceaccount useroot		  #創建服務賬戶
      3 serviceaccount "useroot" created
      4 [student@workstation ~]$ oc login -u admin -p redhat https://master.lab.example.com	#使用集群管理員登錄
      5 [student@workstation ~]$ oc project project-user1			  #選擇項目1
      6 Already on project "project-user1" on server "https://master.lab.example.com:443".
      7 [student@workstation ~]$ oc adm policy add-scc-to-user anyuid -z useroot  #設置SCC策略
      8 scc "anyuid" added to: ["system:serviceaccount:project-user1:useroot"]    #將服務帳戶與anyuid安全上下文關聯,此操作需要集群管理員用戶。
      9 [student@workstation ~]$ oc login -u user2 -p redhat https://master.lab.example.com	#切換user2用戶
     10 [student@workstation ~]$ oc project project-user1
     11 Already on project "project-user1" on server "https://master.lab.example.com:443".
     12 [student@workstation ~]$ oc patch dc nginx --patch='{"spec":{"template":{"spec":{"serviceAccountName": "useroot"}}}}'



    #更新負責管理nginx的dc資源,任何開發人員用戶都可以執行此操作。本環境中,相關操作命令可以從/home/student/DO280/labs/secure-resources文件夾中的configure-sc.sh腳本運行或複製。

    5.12 驗證確認

      1 [student@workstation ~]$ oc get pods
      2 NAME            READY     STATUS    RESTARTS   AGE
      3 nginx-2-98k8f   1/1       Running   0          3m
      4 

    5.13 暴露服務

      1 [student@workstation ~]$ oc expose svc nginx
      2 route "nginx" exposed
      3 [student@workstation ~]$ oc get svc
      4 NAME      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
      5 nginx     ClusterIP   172.30.118.63   <none>        80/TCP    13m
      6 [student@workstation ~]$ oc get route
      7 NAME      HOST/PORT                                  PATH      SERVICES   PORT      TERMINATION   WILDCARD
      8 nginx     nginx-project-user1.apps.lab.example.com             nginx      80-tcp                  None


    5.14 測試訪問

      1 [student@workstation ~]$ curl -s http://nginx-project-user1.apps.lab.example.com

    5.15 策略刪除演示

      1 [student@workstation ~]$ oc login -u admin -p redhat
      2 [student@workstation ~]$ oc adm policy add-cluster-role-to-group self-provisioner system:authenticated system:authenticated:oauth
      3 cluster role "self-provisioner" added: ["system:authenticated" "system:authenticated:oauth"]
      4 [student@workstation ~]$ oc delete project project-user1
      5 project "project-user1" deleted
      6 [student@workstation ~]$ oc delete project project-user2
      7 [root@master ~]# htpasswd -D /etc/origin/master/htpasswd user1 
      8 [root@master ~]# htpasswd -D /etc/origin/master/htpasswd user2


    #為所有常規用戶重新啟用項目創建,即重置為初始狀態。本環境中,相關操作命令可以從/home/student/DO280/labs/secure-resources文件夾中的restore-policy.sh腳本運行或複製。

    六 管理加密信息

    6.1 secret特性


    Secret對象類型提供了一種機制來保存敏感信息,如密碼、OCP客戶端配置文件、Docker配置文件和私有倉庫憑據。Secrets將敏感內容與Pod解耦。可以使用Volume插件將Secrets掛載到容器上,或者系統可以使用Secrets代表pod執行操作。

    Secrets的主要特徵包括:

    • Secrets data可以獨立於其定義引用。
    • Secrets data Volume由臨時文件存儲支持。
    • 可以在名稱空間中共享Secrets data。

    6.2 創建Secrets


    在依賴於該Secrets的pod之前創建一個Secrets。

      1 [user@demo ~]$ oc create secret generic secret_name \
      2 --from-literal=key1=secret1 \
      3 --from-literal=key2=secret2	#用secret data創建secret對象
      4 [user@demo ~]$ oc secrets add --for=mount serviceaccount/serviceaccount-name \
      5 secret/secret_name		#更新pod的服務帳戶,允許引用該secrets。

    例如,允許一個運行在指定服務帳戶下的pod掛載一個secrets

    創建一個pod,該pod使用環境變量或數據卷作為文件的方式使用該secret,通常使用模板完成。

    6.3 使用secret暴露Pod


    secrets可以作為數據卷掛載,也可以作為環境變量以便供pod中的容器使用。

    例如,要向pod公開一個secrets,首先創建一個secrets並將username和password以k/v形式配置,然後將鍵名分配給pod的YAML文件env定義。

    示例:創建名為demo-secret的secrets,它定義用戶名和密碼為username/demo-user。

    [user@demo ~]$ oc create secret generic demo-secret \

    –from-literal=username=demo-user

    要使用前面的secret作為MySQL數據庫pod的數據庫管理員密碼,請定義環境變量,並引用secret名稱和密碼。

      1 env:
      2   - name: MYSQL_ROOT_PASSWORD
      3     valueFrom:
      4       secretKeyRef:
      5        key: username
      6        name: demo-secret


    6.4 web端管理secret


    從web控制台管理secret:

    1. 以授權用戶身份登錄到web控制台。

    2. 創建或選擇一個項目來承載secret。

    3. 導航到resource——>secrets。

    6.5 Secret使用場景


    • password和user names


    敏感信息(如password和user name)可以存儲在一個secret中,該secret被掛載為容器中的數據卷。數據显示為位於容器的數據卷目錄中的文件中的內容。然後,應用程序(如數據庫)可以使用這些secret對用戶進行身份驗證。

    • 傳輸層安全性(TLS)和密鑰對


    通過讓集群將簽名證書和密鑰對生成到項目名稱空間中的secret中,可以實現對服務的通信的保護。證書和密鑰對使用PEM格式存儲以類似tls.crt和tls.key的格式存儲在secret的pod中。

    七 ConfigMap對象

    7.1 ConfigMap概述


    ConfigMaps對象類似於secret,但其設計目的是支持處理不包含敏感信息的字符串。ConfigMap對象持有配置數據的鍵值對,這些配置數據可以在pods中使用,或者用於存儲系統組件(如控制器)的配置數據。

    ConfigMap對象提供了將配置數據注入容器的機制。ConfigMap存儲精細的粒度信息,比如單個屬性,或者詳細信息,比如整個配置文件或JSON blob。

    7.2 CLI創建ConfigMap


    可以使用–from-literal選項從CLI創建ConfigMap對象。

    示例:創建一個ConfigMap對象,該對象將IP地址172.20.30.40分配給名為serverAddress的ConfigMap密鑰。

      1 [user@demo ~]$ oc create configmap special-config \
      2 --from-literal=serverAddress=172.20.30.40
      3 [user@demo ~]$ oc get configmaps special-config -o yaml		#查看configMap
      4 apiVersion: v1
      5 data:
      6   key1: serverAddress=172.20.30.40
      7 kind: ConfigMap
      8 metadata:
      9   creationTimestamp: 2017-07-10T17:13:31Z
     10   name: special-config
     11 ……
     12 在配置映射的pod定義中填充環境變量APISERVER。
     13 env:
     14   - name: APISERVER
     15       valueFrom:
     16         configMapKeyRef:
     17           name: special-config
     18           key: serverAddress


    7.3 web管理ConfigMap


    從web控制台管理ConfigMap對象:

    1. 以授權用戶身份登錄到web控制台。

    2. 創建或選擇一個項目來承載ConfigMap。

    3. 導航到資源→配置映射。

    八 加密練習

    8.1 前置準備


    準備完整的OpenShift集群,參考《003.OpenShift網絡》2.1。

    8.2 本練習準備


    [student@workstation ~]$ lab secure-secrets setup

    8.3 創建項目

      1 [student@workstation ~]$ oc login -u developer -p redhat
      2 [student@workstation ~]$ cd /home/student/DO280/labs/secure-secrets/
      3 [student@workstation secure-secrets]$ less mysql-ephemeral.yml		#導入本環境MySQL模板







    模板解讀:

    該mysql-ephemeral.yml模板文件,包含openshift項目中的mysql臨時模板,pod所需的其他環境變量由模板參數初始化,並具有默認值。

    但沒有secret定義,後續操作將手動創建模板所需的secret。

    根據模板的要求,創建一個包含MySQL容器image使用的憑證的secret,將這個secret命名為mysql。

    • 應用程序訪問的數據庫用戶名由database-user定義。
    • 數據庫用戶的密碼由database-password定義。
    • 數據庫管理員密碼由database-root-password定義

    8.4 創建新secret

      1 [student@workstation secure-secrets]$ oc create secret generic mysql \
      2 --from-literal='database-user'='mysql' \
      3 --from-literal='database-password'='redhat' \
      4 --from-literal='database-root-password'='do280-admin'
      5 [student@workstation secure-secrets]$ oc get secret mysql -o yaml	#確認secret




    8.5 創建應用

      1 [student@workstation secure-secrets]$ oc new-app --file=mysql-ephemeral.yml
      2 [student@workstation secure-secrets]$ oc get pods		#確認應用
      3 NAME            READY     STATUS    RESTARTS   AGE
      4 mysql-1-j4fnz   1/1       Running   0          1m


    8.6 端口轉發

      1 [student@workstation secure-secrets]$ cd
      2 [student@workstation ~]$ oc port-forward mysql-1-j4fnz 3306:3306



    提示:驗證完成之前forward不要關閉。

    8.7 確認驗證

      1 [student@workstation ~]$ mysql -uroot -pdo280-admin -h127.0.0.1	#新開終端測試MySQL



    九 管理security policy

    9.1 OCP authorization授權


    OCP定義了用戶可以執行的兩組主要操作:

    與項目相關的操作(也稱為本地策略):project-related

    與管理相關的操作(也稱為集群策略):administration-related

    由於這兩種策略都有大量可用的操作,所以將一些操作分組並定義為角色。














    默認角色 描述
    cluster-admin 此角色中的所有用戶都可以管理OpenShift集群。
    cluster-status 此角色中的所有用戶都提供對集群信息的只讀訪問。


    為管理本地政策,OCP提供以下角色:




















    默認角色 描述
    edit 角色中的用戶可以從項目中創建、更改和刪除公共應用程序資源,比如service和dc。 但是不能對限制範圍和配額等管理資源採取行動,也不能管理對項目的訪問權限。
    basic-user 角色中的用戶具有對項目的讀訪問權。
    self-provisioner 角色中的用戶可以創建新項目。這是一個集群角色,而不是項目角色。
    admin 角色中的用戶可以管理項目中的所有資源,包括授予對項目的其他用戶的訪問權


    除了能夠創建新應用程序之外,admin角色還允許用戶訪問項目資源,比如配額和限制範圍。

    edit角色允許用戶在項目中充當開發人員,但要在項目管理員配置的約束下工作。

    9.2 相關命令

      1 向集群用戶添加角色
      2 $ oc adm policy add-cluster-role-to-user cluster-role username
      3 示例:將普通用戶更改為集群管理員。
      4 $ oc adm policy add-cluster-role-to-user cluster-role username
      5 從用戶中刪除集群角色
      6 $ oc adm policy remove-cluster-role-from-user cluster-role username
      7 示例:將集群管理員更改為普通用戶。
      8 $ oc adm policy remove-cluster-role-from-user cluster-admin username
      9 將指定的用戶綁定到項目中的角色
     10 $ oc adm policy add-role-to-user role-name username -n project
     11 示例:在WordPress項目中dev用戶綁定basic-user角色。
     12 $ oc adm policy add-role-to-user basic-user dev -n wordpress


    9.3 權限及規則


    OpenShift將一組規則集合成一個角色,規則由謂詞和資源定義。如create user是OpenShift中的一條規則,它是一個名為cluster-admin的角色的所擁有的權限的一部分。

      1 $ oc adm policy who-can delete user

    9.4 user類型


    與OCP的交互基於用戶,OCP的user對象表示可以通過向該用戶或用戶組添加角色來從而實現相應權限的授予。

    Regular users:通常以這種用戶類型與OCP交互,常規用戶用User對象表。例如,user1,user2。

    System users:通常在安裝OCP中定義基礎設施時自動創建的,主要目的是使基礎設施能夠安全地與API交互。包括集群管理員(可以訪問所有內容)、每個節點的用戶、路由器和內部倉庫使用的用戶,以及各種其他用戶。還存在一個匿名系統用戶,默認情況下,該用戶用於未經身份驗證的請求。system user主要包括:system:admin、system:openshift-registry和system:node:node1.example.com。

    Service accounts:這些是與項目關聯的特殊系統用戶。有些是在第一次創建項目時自動創建的,項目管理員可以創建多個,以便定義對每個項目內容的訪問。Service accounts由ServiceAccount對象表示。Service accounts主要包括:system:serviceaccount:default:deployer和system:serviceaccount:foo:builder。

    每個用戶在訪問OpenShift容器平台之前必須進行身份驗證。沒有身份驗證或身份驗證無效的API請求將使用匿名系統用戶身份驗證來請求服務。身份驗證成功后,策略確定用戶被授權做什麼。

    9.5 安全上下文約束(SCCS)


    OpenShift提供了一種名為安全上下文約束的安全機制,它限制對資源的訪問,但不限制OpenShift中的操作。

    SCC限制從OpenShift中運行的pod到主機環境的訪問:

    • 運行特權容器
    • 請求容器的額外功能
    • 使用主機目錄作為卷
    • 更改容器的SELinux上下文
    • 更改用戶ID


    社區開發的一些容器可能需要放鬆安全上下文約束,因為它們可能需要訪問默認禁止的資源,例如文件系統、套接字或訪問SELinux上下文。

    OpenShift定義的安全上下文約束(SCCs)可以使用以下命令作為集群管理員列出。

    $ oc get scc

    SCC通常有以下7中SCCS:

    • anyuid
    • hostaccess
    • hostmount-anyuid
    • nonroot
    • privileged
    • restricted(默認)


    $ oc describe scc anyuid #查看某一種SCC詳情

    OpenShift創建的所有容器都使用restricted類型的SCC,它提供了對OpenShift外部資源的有限訪問。

    對於anyuid安全上下文,run as user策略被定義為RunAsAny,表示pod可以作為容器中可用的任何用戶ID運行。這允許需要特定用戶使用特定用戶ID運行命令的容器。

    要將容器更改為使用不同的SCC運行,需要創建綁定到pod的服務帳戶。

    $ oc create serviceaccount service-account-name #首先創建服務賬戶

    $ oc adm policy add-scc-to-user SCC -z service-account #將服務帳戶與SCC關聯

    要確定哪個帳戶可以創建需要更高安全性要求的pod,可以使用scc-subject-review子命令。

    $ oc export pod pod-name > output.yaml

    $ oc adm policy scc-subject-review -f output.yaml

    9.6 OpenShift與SELinux


    OpenShift要求在每個主機上啟用SELinux,以便使用強制訪問控制提供對資源的安全訪問。同樣,由OpenShift管理的Docker容器需要管理SELinux上下文,以避免兼容性問題。

    為了最小化在不支持SELinux的情況下運行容器的風險,可以創建SELinux上下文策略。

    為了更新SELinux上下文,可以使用現有的SCC作為起點生成一個新的SCC。

    $ oc export scc restricted > custom_selinux.yml #導出默認的SCC

    編輯導出的YAML文件以更改SCC名稱和SELinux上下文。

    $ oc create -f yaml_file #使用修改后的ymal重新創建一個SCC

    9.7 特權容器


    有些容器可能需要訪問主機的運行時環境。S2I構建器容器需要訪問宿主docker守護進程來構建和運行容器。

    例如,S2I構建器容器是一類特權容器,它要求訪問超出其自身容器的限制。這些容器可能會帶來安全風險,因為它們可以使用OpenShift節點上的任何資源。通過創建具有特權訪問權的服務帳戶,可以使用SCCs啟用特權容器的訪問。

    十 資源訪問控制綜合實驗

    10.1 前置準備


    準備完整的OpenShift集群,參考《003.OpenShift網絡》2.1。

    10.2 本練習準備

      1 [student@workstation ~]$ lab secure-review setup

    10.3 創建用戶

      1 [root@master ~]# htpasswd /etc/origin/master/htpasswd user-review
      2 New password: 【redhat】
      3 Re-type new password: 【redhat】


    10.4 修改策略

      1 [student@workstation ~]$ oc login -u admin -p redhat
      2 [student@workstation ~]$ oc adm policy remove-cluster-role-from-group \
      3 self-provisioner system:authenticated system:authenticated:oauth
      4 禁用所有常規用戶的項目創建功能


    10.5 確認驗證

      1 [student@workstation ~]$ oc login -u user-review -p redhat
      2 [student@workstation ~]$ oc new-project test			#普通用戶無法創建項目
      3 Error from server (Forbidden): You may not request a new project via this API.


    10.6 創建項目

      1 [student@workstation ~]$ oc login -u admin -p redhat
      2 [student@workstation ~]$ oc new-project secure-review		#使用管理員創建項目


    10.7 授權用戶

      1 [student@workstation ~]$ oc project secure-review
      2 Already on project "secure-review" on server "https://master.lab.example.com:443".
      3 [student@workstation ~]$ oc policy add-role-to-user edit user-review	#將edit的role和user-review進行關聯


    10.8 測試訪問

      1 [student@workstation ~]$ oc login -u user-review -p redhat
      2 [student@workstation ~]$ oc project secure-review		#測試訪問
      3 Already on project "secure-review" on server "https://master.lab.example.com:443".


    10.9 檢查模板

      1 [student@workstation ~]$ cd /home/student/DO280/labs/secure-review/
      2 [student@workstation secure-review]$ less mysql-ephemeral.yml





    模板解讀:

    該mysql-ephemeral.yml模板文件,包含openshift項目中的mysql臨時模板,pod所需的其他環境變量由模板參數初始化,並具有默認值。

    但沒有secret定義,後續操作將手動創建模板所需的secret。

    根據模板的要求,創建一個包含MySQL容器image使用的憑證的secret,將這個secret命名為mysql。

    • 應用程序訪問的數據庫用戶名由database-user定義。
    • 數據庫用戶的密碼由database-password定義。
    • 數據庫管理員密碼由database-root-password定義


    使用user-review developer用戶創建一個名為mysql的secret。這個secret應該存儲用戶名mysql、密碼redhat和數據庫管理員密碼do280-admin。

    數據庫用戶名由database-user定義。此用戶的密碼由mysql secret密鑰定義。

    數據庫管理員密碼由database-root-password定義。

    10.10 創建secret

      1 [student@workstation secure-review]$ oc create secret generic mysql \
      2 --from-literal='database-user'='mysql' \
      3 --from-literal='database-password'='redhat' \
      4 --from-literal='database-root-password'='do280-admin'
      5 [student@workstation secure-review]$ oc get secret mysql -o yaml	#確認驗證secret


    10.11 部署應用

      1 [student@workstation secure-review]$ oc new-app --file=mysql-ephemeral.yml
      2 [student@workstation secure-review]$ oc get pods
      3 NAME            READY     STATUS    RESTARTS   AGE
      4 mysql-1-2lr7t   1/1       Running   0          31s


    10.12 轉發端口

      1 [student@workstation ~]$ oc port-forward mysql-1-2lr7t 3306:3306

    10.13 測試訪問

      1 [student@workstation ~]$ mysql -umysql -predhat -h127.0.0.1

    10.14 部署phpmyadmin應用


    使用內部倉庫registry.lab.example.com的image部署phpmyadmin:4.7容器。phpmyadmin:4.7容器需要名為PMA_HOST的環境變量來提供MySQL服務器的IP地址。

    使用模板創建一個基於FQND的MySQL pod的service。

    為使用模板創建的MySQL服務器pod使用服務FQDN,該模板是mysql.secure-review.svc.cluster.local。

      1 [student@workstation ~]$ oc new-app --name=phpmyadmin \
      2 --docker-image=registry.lab.example.com/phpmyadmin/phpmyadmin:4.7 \
      3 -e PMA_HOST=mysql.secure-review.svc.cluster.local






    結論:該命令會發出警告,提示需要root特權。默認情況下,OpenShift不支持使用操作系統的root用戶運行容器。

    10.15 查看pod

      1 [student@workstation ~]$ oc get pods
      2 NAME                 READY     STATUS    RESTARTS   AGE
      3 mysql-1-2lr7t        1/1       Running   0          8m
      4 phpmyadmin-1-v7tl7   0/1       Error     2          1m
      5 因為沒有root權限,因此部署失敗,需要提權。


    10.16 授予權限

      1 [student@workstation ~]$ oc login -u admin -p redhat			#使用管理員登錄
      2 [student@workstation ~]$ oc create serviceaccount phpmyadmin-account	#首先創建服務賬戶
      3 [student@workstation ~]$ oc adm policy add-scc-to-user anyuid -z phpmyadmin-account
      4 scc "anyuid" added to: ["system:serviceaccount:secure-review:phpmyadmin-account"]	#將服務帳戶與anyuid安全上下文關聯


    10.17 更新應用

      1 [student@workstation ~]$ oc patch dc phpmyadmin --patch='{"spec":{"template":{"spec":{"serviceAccountName": "phpmyadmin-account"}}}}'


    #更新負責管理phpmyadmin的dc資源,任何開發人員用戶都可以執行此操作。

    本環境中,相關操作命令可以從/home/student/DO280/labs/secure-review文件夾中的patch-dc.sh腳本運行或複製。

    10.18 確認驗證

      1 [student@workstation ~]$ oc login -u user-review -p redhat
      2 [student@workstation ~]$ oc get pods			#確認pod是否正常
      3 NAME                 READY     STATUS    RESTARTS   AGE
      4 mysql-1-2lr7t        1/1       Running   0          13m
      5 phpmyadmin-2-bdjvq   1/1       Running   0          1m


    10.19 暴露服務

      1 [student@workstation ~]$ oc expose svc phpmyadmin --hostname=phpmyadmin.apps.lab.example.com

    10.20 訪問測試

      1 [student@workstation ~]$ curl -s http://phpmyadmin.apps.lab.example.com

    10.21 確認及刪除

      1 [student@workstation ~]$ lab secure-review grade		#環境腳本判斷
      2 [student@workstation ~]$ oc login -u admin -p redhat
      3 [student@workstation ~]$ oc adm policy add-cluster-role-to-group \
      4 self-provisioner system:authenticated system:authenticated:oauth
      5 [student@workstation ~]$ oc delete project secure-review
      6 [student@workstation ~]$ ssh root@master htpasswd -D \
      7 /etc/origin/master/htpasswd user-review			#刪除用戶
      8 [student@workstation ~]$ oc delete user user-review		#刪除項目

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※教你寫出一流的銷售文案?

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※回頭車貨運收費標準

    ※別再煩惱如何寫文案,掌握八大原則!

    ※超省錢租車方案

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!