整合營銷服務商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          在asp.net core 中控制訪問權限的方法

          在asp.net core 中控制訪問權限的方法



          ntro#

          由于項目需要,需要在基于 asp.net mvc 的 Web 項目框架中做權限的控制,于是才有了這個權限控制組件,最初只是支持 netframework,后來 dotnetcore 2.0 發(fā)布了之后添加了對 asp.net core 的支持,在 dotnetcore 3.0 發(fā)布之后也增加了對 asp.net core 3.0 的支持(1.9.0及之后版本),目前對于 asp.net core 支持的更多一些,asp.net core 可以使用 TagHelper 來控制頁面上元素的權限訪問,也可以通過 Policy 來控制權限訪問,同時支持通過中間件也可以實現(xiàn)對靜態(tài)資源的訪問。

          安裝 AccessControlHelper nuget 包#

          安裝 nuget 包 WeihanLi.AspNetMvc.AccessControlHelper

          Copydotnet add package WeihanLi.AspNetMvc.AccessControlHelper
          

          實現(xiàn)自己的訪問策略#

          資源訪問策略/API訪問策略#

          以下代碼定義了一個簡單的訪問策略,需要登錄且擁有 Admin 角色,可以根據(jù)自己需要調(diào)整優(yōu)化

          Copypublic class AdminPermissionRequireStrategy : IResourceAccessStrategy
          {
              private readonly IHttpContextAccessor _accessor;
          
              public AdminPermissionRequireStrategy(IHttpContextAccessor accessor)
              {
                  _accessor=accessor;
              }
          
              public bool IsCanAccess(string accessKey)
              {
                  var user=_accessor.HttpContext.User;
                  return user.Identity.IsAuthenticated && user.IsInRole("Admin");
              }
          
              public IActionResult DisallowedCommonResult=> new ContentResult
              {
                  Content="No Permission",
                  ContentType="text/plain",
                  StatusCode=403
              };
          
              public IActionResult DisallowedAjaxResult=> new JsonResult(new JsonResultModel
              {
                  ErrorMsg="No Permission",
                  Status=JsonResultStatus.NoPermission
              });
          }
          

          頁面元素訪問策略#

          定義頁面元素/控件訪問策略:

          Copypublic class AdminOnlyControlAccessStrategy : IControlAccessStrategy
          {
              private readonly IHttpContextAccessor _accessor;
          
              public AdminOnlyControlAccessStrategy(IHttpContextAccessor httpContextAccessor)=> _accessor=httpContextAccessor;
          
              public bool IsControlCanAccess(string accessKey)
              {
                  if ("Never".Equals(accessKey, System.StringComparison.OrdinalIgnoreCase))
                  {
                      return false;
                  }
                  var user=_accessor.HttpContext.User;
                  return user.Identity.IsAuthenticated && user.IsInRole("Admin");
              }
          }
          

          服務注冊配置#

          在 Startup 里注冊服務:

          Copyservices.AddAccessControlHelper()
              .AddResourceAccessStrategy<AdminPermissionRequireStrategy>()
              .AddControlAccessStrategy<AdminOnlyControlAccessStrategy>()
              ;
          

          如果你只是 web api ,不涉及到頁面元素的權限控制可以只注冊 ResourceAccessStrategy

          Copyservices.AddAccessControlHelper()
          .AddResourceAccessStrategy<AdminPermissionRequireStrategy>();
          

          默認訪問策略的生命周期是單例的,如果需要注冊為Scoped,可以指定默認的生命周期

          Copyservices.AddAccessControlHelper()
          .AddResourceAccessStrategy<AdminPermissionRequireStrategy>(ServiceLifetime.Scoped);
          

          API/資源的權限控制#

          對于 asp.net core 應用推薦使用 Policy 來控制權限的訪問,可以在需要權限控制的 Action 或者 Controller 上設置 [Authorize("AccessControl")] 或者 [Authorize(AccessControlHelperConstants.PolicyName)]

          Copy[Authorize(AccessControlHelperConstants.PolicyName)]
          public class SystemSettingsController : AdminBaseController
          {
              // ...
          }
          
          Copy[Authorize(AccessControlHelperConstants.PolicyName)]
          public ActionResult UserList()
          {
              return View();
          }
          

          頁面元素的權限控制#

          引用 TagHelper#

          在 Views 目錄下的 _ViewImports.cshtml 文件中導入 AccessControlHelper 的 TagHelper

          Copy@using ActivityReservation
          @using WeihanLi.AspNetMvc.AccessControlHelper
          @using WeihanLi.AspNetMvc.MvcSimplePager
          
          @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
          @addTagHelper *, WeihanLi.AspNetMvc.AccessControlHelper
          

          頁面元素配置#

          在需要權限控制的元素上增加 asp-access 的 attribute 就可以了,如果需要 access-key 通過 asp-access-key 來配置

          Copy<ul class="list-group" asp-access asp-access-key="AdminOnly">
              <li role="separator" class="list-unstyled">
                  <br />
              </li>
              <li class="list-group-item">@Html.ActionLink("用戶管理", "UserList", "Account")</li>
          
              <li class="list-group-item">@Html.ActionLink("操作日志查看", "Index", "OperationLog")</li>
              <li class="list-group-item">@Html.ActionLink("系統(tǒng)設置管理", "Index", "SystemSettings")</li>
              <li class="list-group-item">
                  @Html.ActionLink("微信設置管理", "Index", new {
                  controller="Config",
                  area="Wechat"
              })
              </li>
          </ul>
          

          這樣就可以了,有權限訪問的時候才會正常渲染,沒有權限訪問的時候,這一段 ul 并不會渲染輸出,在客戶端瀏覽器查看源代碼也不會看到對應的代碼

          ormMaking介紹

          FormMaking表單設計器是一款與行業(yè)無關的通用表單設計器前端解決方案,表單設計器包含設計器(MakingForm)和生成器(GenerateForm)兩個模塊,設計器主要負責表單的動態(tài)設計,可以通過拖拽的形式設計生成表單頁面,生成器則負責對表單頁面的渲染和數(shù)據(jù)的回寫。

          如果你對FormMaking不太了解可能會把FormMaking當成是單純頁面設計器,只為了減少重復的表單,稍微有點經(jīng)驗的前端開發(fā),通過簡單的Copy Paste就能很快做出一個固定的表單頁面。而FormMaking做的是一整套與表單相關的前端方案,包含了表單的動態(tài)設計,表單渲染,數(shù)據(jù)回寫,數(shù)據(jù)校驗,事件支持,css自定義,動作面板等豐富的功能,而這些所有的功能只需要一個import 命令將MakingFormGenerateForm引入到項目中,你的項目就可以擁有這些功能。

          FormMaking新功能 自定義字段高級用法

          FormMaking基礎功能可以看之前都介紹。

          本文我們將介紹如何使用 FormMaking 來引入自己的高級組件,并可以通過設計器進行配置,處理事件等操作

          封裝分頁數(shù)據(jù)表格組件

          我們將封裝 一個分頁數(shù)據(jù)表格組件,組件采用 ElementPlus TableV2

          <template>
            <div>
              <div style="height: 400px">
                <el-auto-resizer>
                  <template #default="{ height, width }">
                    <el-table-v2
                      :columns="columns"
                      :data="data"
                      :width="width"
                      :height="height"
                      fixed
                    />
                  </template>
                </el-auto-resizer>
              </div>
              <el-pagination 
                background 
                layout="prev, pager, next" 
                :total="1000" 
                v-model:current-page="currentPage"
                @current-change="loadPageData"
              />
            </div>
          </template>
          
          <script setup>
          import { onMounted, ref, watch } from 'vue'
          
          const props=defineProps({
            modelValue:  {
              type: Array,
              default: ()=> []
            },
            columns: {
              type: Array,
              default: ()=> []
            }
          })
          
          const emit=defineEmits(['on-load'])
          
          const data=ref(props.modelValue)
          
          const currentPage=ref(1)
          
          const loadPageData=(index)=> {
            // 通過 emit,可以將事件拋出到設計器中進行配置
            emit('on-load', index)
          }
          
          onMounted(()=> {
            emit('on-load', currentPage.value)
          })
          
          watch(()=> props.modelValue, (val)=> {
            data.value=val
          })
          </script>
          


          引入到設計器

          注冊組件

          首先應該在自己項目中進行組件的注冊。

          import CustomPaginationTable from 'PaginationTable.vue'
          
          app.use(FormMakingV3, {
            components: [{
              name: 'custom-pagination-table',
              component: CustomPaginationTable // 自定義組件
            }]
          })

          也可以使用Vue.component 進行組件的注冊

          app.component('custom-pagination-table', CustomPaginationTable)

          設計器配置

          <template>
          <fm-making-form
            :custom-fields="customFields"
          >
            </fm-making-form>
          </template>
          
          <script>
            export default {
              data() {
                return {
                  customFields: [
                    {
                      name: '分頁數(shù)據(jù)列表',
                      el: 'custom-pagination-table',
                      options: {
                        defaultValue: [],
                        labelWidth: 0,
                        isLabelWidth: false,
                        hidden: false,
                        dataBind: true,
                        validator: '',
                        extendProps: {
                          columns: [] // 用于配置表格的列
                        }
                      },
                      events: {
                        onLoad: '' // 定義設計器可以配置的事件,處理組件 emit 的事件
                      }
                    }
                  ]
                }
              }
            }
          </script>

          然后在自定義字段中就展示出來了


          設計器界面

          配置組件表格

          表格列配置

          在字段屬性中對擴展屬性配置 進行設置



          數(shù)據(jù)加載

          數(shù)據(jù)加載的 on-load事件,我們在自定義組件中通過emit拋出到設計器中進行配置,在字段屬性-動作設置中添加onLoad事件配置如下:

          效果展示

          我們來查看下最后的效果

          效果圖

          更多關于FormMaking詳情可移步:

          可視化低代碼表單設計器 - FormMaking

          寶頁面比較復雜,含有各種請求參數(shù)和加密參數(shù),如果直接請求或者分析Ajax將會非常繁瑣。Selenium是一個自動化測試工具,可以驅(qū)動瀏覽器去完成各種工作,比如模擬點擊、輸入和下拉等多種功能,這樣我們只需關心操作,不需要關心后臺發(fā)生了怎么樣的請求下面對具體操作步驟進行詳述

          實現(xiàn)流程

          1.搜索關鍵字:利用Selenium驅(qū)動瀏覽器搜索關鍵字,得到查詢后的商品列表

          2.分析頁碼并翻頁:得到商品頁碼數(shù),模擬翻頁,得到后續(xù)頁面的商品列表

          3.分析提取商品內(nèi)容:利用PyQuery分析源碼,解析得到商品列表

          4.存儲至MongoDB:將商品列表信息存儲到數(shù)據(jù)庫MongoDB

          具體實現(xiàn)

          1.首先需要聲明一個browser用來操作,我的是chrome。這里的wait是在后面的判斷元素是否出現(xiàn)時使用,第二個參數(shù)為等待最長時間,超過該值則拋出異常

          #創(chuàng)建一個瀏覽器對象
          browser=webdriver.Chrome()
          #十秒內(nèi)尋找元素失敗,將報出TimeoutException異常
          wait=WebDriverWait(browser, 10)
          

          2.聲明好之后就需要進行打開網(wǎng)頁、進行搜索的操作

          def search():
           """
           作用:通過關鍵字搜索得到搜索內(nèi)容第一頁產(chǎn)品信息,并返回搜索內(nèi)容共計頁碼
           """
           print('正在搜索')
           try: 
           browser.get('https://www.taobao.com')
           print(browser.page_source)
           
           # 獲取input輸入框?qū)ο?
           input=wait.until(
           EC.presence_of_element_located((By.CSS_SELECTOR, "#q")) 
           )#
           # 獲取button提交對象
           submit=wait.until(
           EC.element_to_be_clickable(
           (By.CSS_SELECTOR, "#J_TSearchForm > div.search-button > button")
           )
           )
           # KEYWORD是config.py文件中定義的搜索關鍵字,可修改
           input.send_keys(KEYWORD)
           # 點擊button提交按鈕
           submit.click()
           # 通過CSS_SELECTOR選擇器獲取total頁碼
           total_page=wait.until(
           EC.presence_of_element_located(
           (By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.total")
           ) 
           )
           # 解析頁面內(nèi)容,并將數(shù)據(jù)保存至MongoDB中
           get_products()
           return total_page.text
           except TimeoutException:
           # 出現(xiàn)超時訪問就重新調(diào)用一次search
           return search()
          

          3.第一個頁面操作之后,我們需要進行翻頁操作,如下:

          def next_page(page_number):
           """
           作用:作人為翻頁功能,并得到該頁產(chǎn)品信息
           page_number:循環(huán)的頁碼,將頁碼寫入input框中
           """
           print('正在翻頁', page_number)
           
           try:
           # 獲取input輸入框?qū)ο?
           input=wait.until(
           EC.presence_of_element_located(
           (By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > input")
           ) 
           )
           # 獲取button提交對象
           submit=wait.until(
           EC.element_to_be_clickable(
           (By.CSS_SELECTOR, "div > div > div > div.form > span.btn.J_Submit")
           )
           )
           # 將input框清空
           input.clear()
           # 向input框中輸入頁碼
           input.send_keys(page_number)
           # 點擊button提交按鈕
           submit.click()
           wait.until(
           # 驗證輸入框內(nèi)的頁碼是否為當前高亮頁碼,如果是,則繼續(xù)執(zhí)行
           # text參數(shù)是否在該span元素內(nèi),此處需要注意text的參數(shù)位置
           EC.text_to_be_present_in_element(
           (By.CSS_SELECTOR, '#mainsrp-pager > div > div > div > ul > li.item.active > span'), str(page_number)
           )
           )
           
           # 獲取產(chǎn)品信息并保存至MongoDB
           get_products()
           except TimeoutException:
           # 超時異常,則繼續(xù)解析該頁
           next_page(page_number)
          

          4.寫完搜索操作和翻頁操作后,我們需要完成對每個頁面的商品信息獲取功能

          def get_products():
           """
           作用:通過頁面源代碼,將產(chǎn)品信息保存至MongoDB中
           """
           # 通過CSS_SELECTOR選擇器,驗證頁面中是否存在產(chǎn)品對象
           wait.until(
           EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-itemlist .items .item"))
           )
           # 拿到頁面源碼
           html=browser.page_source
           
           # 通過pyquery找到產(chǎn)品對象
           doc=pq(html)
           items=doc('#mainsrp-itemlist .items .item').items()
           # 遍歷每個產(chǎn)品對象,組建數(shù)據(jù)內(nèi)容
           for item in items:
           product={
           'image': item.find('.pic .img').attr('src'),
           'price': item.find('.price').text(),
           'deal': item.find('.deal-cnt').text()[:-3],
           'title': item.find('.title').text(),
           'shop': item.find('.shop').text(),
           'location': item.find('.location').text()
           }
           # print(product)
           # 將組建好的每個產(chǎn)品信息保存至MongoDB
           save_to_mongo(product)
          

          5.獲取信息之后則需要對信息進行存儲,將數(shù)據(jù)庫關鍵參數(shù)定義在config.py文件中

          #!/usr/bin/env python
          # coding=utf-8
          # 本地的數(shù)據(jù)庫
          MONGO_URL='localhost'
          # 數(shù)據(jù)庫的名稱
          MONGO_DB='taobao'
          # 數(shù)據(jù)庫的表名
          MONGO_TABLE='products'
          

          6.將組建好的每個產(chǎn)品信息保存至MongoDB

          # 創(chuàng)建一個MongoDB對象
          client=pymongo.MongoClient(MONGO_URL)
          # 創(chuàng)建一個數(shù)據(jù)庫,注意是[]而不是()
          db=client[MONGO_DB]
          def save_to_mongo(result):
           """
           作用:將信息保存至MongoDB中
           """
           try:
           if db[MONGO_TABLE].insert(result):
           print('Successfully save to MongoDB', result)
           
           except Exception:
           print('Failed save to MongoDB', result)
          

          7.爬取調(diào)度器

          def TbMeishi_Spider():
           """
           作用:淘寶美食爬取調(diào)度器
           """
           try:
           total_page=search()
           # 通過正則將search返回的total頁碼內(nèi)容解析成數(shù)字形式
           pattern=re.compile('(\d+)')
           total_page=int(pattern.search(total_page).group(1))
           # print(total_page)
           # 遍歷頁碼,傳入next_page函數(shù)中,做整站爬取
           for i in range(2, total_page + 1):
           next_page(i)
           
           except Exception:
           print('有錯誤產(chǎn)生...')
           
           finally:
           browser.close()
          

          8.代碼完成到這里已經(jīng)可以結束了,但是使用Selenium模擬會發(fā)現(xiàn)每次運行程序都會打開一個瀏覽器,然后自動操作,可以最直接地觀察到代碼的運行,但是假如不想彈出瀏覽器的話,可以使用PhantomJS來實現(xiàn)一個無界面的webkit瀏覽器。雖然沒有界面,但dom渲染、js運行、網(wǎng)絡訪問、canvas/svg繪制等功能都很完備,在頁面抓取、頁面輸出、自動化測試等方面有廣泛的應用。下載PhantomJS地址:http://phantomjs.org/download.html,下載完成后解壓縮,將PhantomJS添加到環(huán)境變量中即可

          在config.py文件中加上

          # 關閉load-images的功能,加快運行速度,默認開啟,開啟disk-cache緩存,默認關閉
          SERVICE_ARGS=['--load-images=false', '--disk-cache=true']
          # 無界面瀏覽器,將browser改為
          browser=webdriver.PhantomJS(service_args=SERVICE_ARGS)
          # 設置PlantomJS的窗口大小,可能會影響內(nèi)容下載
          browser.set_window_size(1400, 900)
          

          總結思考

          1.目標網(wǎng)址不匹配

          一開始使用顯示等待訪問,通過CSS_SELECTOR的id選擇器找到網(wǎng)頁元素,可最后程序都執(zhí)行異常,每次都是TimeoutExceptions的異常錯誤。經(jīng)過反復排查,才發(fā)現(xiàn)淘寶網(wǎng)有很多個站點

          我在程序中使用的是:http://www.taobao.com

          但是在進行網(wǎng)頁分析的時候隨意用百度搜了一個淘寶站點,它的站點是:https://uland.taobao.com/sem/tbsearch

          兩個站點地址不一樣,網(wǎng)頁元素也不一樣,自己竟然會犯這種錯誤,應牢記,正確的選擇元素應該是下面這幾行

          from selenium.webdriver.common.by import By
          from selenium.webdriver.support.ui import WebDriverWait
          from selenium.webdriver.support import expected_conditions as EC
          input=WebDriverWait(browser, 10).until(
           EC.presence_of_element_located((By.ID, 'q'))
          )
          button=WebDriverWait(browser, 10).until(
           EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search'))
          )
          

          2.text參數(shù)是否在該span元素內(nèi),此處需要注意text的參數(shù)位置

          # 驗證text參數(shù)是否與選擇器選擇的元素文本內(nèi)容一致
          text_to_be_present_in_element(locator, text_)
          

          3.完整源碼地址:https://github.com/XiaoFei-97/TbMeishi_Spider\


          主站蜘蛛池模板: 亚洲性日韩精品国产一区二区| 波多野结衣中文字幕一区 | 国产一区二区不卡在线播放| 天堂不卡一区二区视频在线观看 | 亚洲av片一区二区三区| 免费高清在线影片一区| 亚洲AV无码一区东京热| 亚洲午夜日韩高清一区| 日韩精品一区二区三区影院| 国产怡春院无码一区二区| 中文字幕一区精品| 日韩精品一区二区三区视频 | 国产成人一区二区三区免费视频| 91视频国产一区| 国产一区二区三区樱花动漫| 国产在线第一区二区三区| 精品成人av一区二区三区| 伊人色综合网一区二区三区| 国产一区二区三区精品久久呦| 无码人妻精品一区二区三区久久| 免费一区二区三区四区五区| 中文字幕无码免费久久9一区9| 亚洲AV香蕉一区区二区三区| 精品亚洲一区二区| 国产日韩高清一区二区三区| 国产成人精品一区二区秒拍| 亚洲AV网一区二区三区| 日本一区二区三区在线观看| 精品一区二区三区在线视频| 九九无码人妻一区二区三区| 天堂资源中文最新版在线一区| 天码av无码一区二区三区四区| 亚洲国产精品一区二区久久hs| 亚洲一区二区三区在线网站| 八戒久久精品一区二区三区| 亚洲乱码国产一区网址| 亚洲一区二区三区丝袜| 无码一区二区三区爆白浆| 精品国产乱子伦一区二区三区 | 麻豆AV一区二区三区久久| 国产一区二区三区韩国女主播|