買電動車送補貼金?傳德國財政部提12億歐元獎勵方案

德國電動車銷售積弱不振,據傳財政部已提出總額12億歐元(相當於13.5億美元)的補貼法案,希望為電動車市重新注入活力,而所需費用將由政府及車商聯手買單。

華爾街日報25日引述未具名消息人士報導,德國政府高層和汽車產業代表即將在26日與德國總理梅克爾會面,討論刺激電動車銷售量的獎勵措施,另外也會考慮直接由政府出資、在全國建設充電站。

根據財政部提出的建議,在2016年至2018年夏季期間,購買電動車的民眾可獲得政府與車商補貼5,000歐元,購買油電混合動力車的民眾則可獲得3,000歐元的補助,在此之後補貼金額會分別下降至3,000歐元(電動車)、2,000歐元(油電混合動力車)。

消息顯示,售價高於60,000歐元的電動車不在補助範圍之內,以免獎勵措施淪為補貼富人買車的工具。另外,這個方案將遵循先買先補貼的原則,12億歐元的補助款用罄之後將不再補款。財政部也提議提供3億歐元的額外補貼,為電動車設立充電站。

Thomson Reuters報導,梅克爾甫於4月12日呼籲汽車製造商開出願望清單。梅克爾表示,官方將盡快清除法律障礙、讓他們可以在德國測試無人駕駛車。她透露,德國執政聯盟將在5月底開會討論自駕車法令規範。德國財長Wolfgang Schaeuble上個月說,官方將設法協助電動車開發、但可能無法讓所有車商感到滿意。車界領袖呼籲,德國若想維持全球領導地位、政府就得想辦法提振電動車買氣。

蘋果在德國的電動車開發案似乎正進行的如火如荼。AppleInsider 4月18日引述法蘭克福廣訊報(Frankfurter Allgemeine Zeitung)報導,蘋果已在柏林設立秘密開發實驗室,目前在當地擁有15-20名工程、軟體、硬體、行銷背景的德國汽車業頂尖人才。報導指出,蘋果進軍汽車業的第一款產品將是電動車、但初期不具備自駕功能。

(本文內容由授權提供)

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

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

ASP.NET Core 3.0 gRPC 身份認證和授權

一.開頭聊騷

本文算是對於 ASP.NET Core 3.0 gRPC 研究性學習的最後一篇了,以後在實際使用中,可能會發一些經驗之文。本文主要講 ASP.NET Core 本身的認證授權和gRPC接入,認證方式採用目前主流的 JWT 結合 IdentityServer4。

二.服務端配置

我們首先需要在服務端配置認證和授權。gRPC基於此文的Demo來開始: ,IdentityServer 基於此文Demo: 。

配置

1.首先啟動 IdentityServer4 地址為:

2.為gRPC項目安裝Jwt組件:Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 3.0.0

3.為gRPC項目配置認證和授權服務

在 Startup 類的 ConfigureServices 方法中,配置如下代碼

services.AddAuthorization(options =>
{
    options.AddPolicy(JwtBearerDefaults.AuthenticationScheme, policy =>
    {
        policy.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme);
        policy.RequireClaim("sub");
    });
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "http://localhost:5000";
        options.RequireHttpsMetadata = false;
        options.Audience = "grpc1";
    });

4.啟用認證授權中間件

在 Startup 類的 Configure 方法中,配置如下代碼

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

請務必注意中間件順序

5.為gRPC服務啟用授權

我們在 LuCatService 的 SuckingCat 方法上,加上 [Authorize]特性,就和在MVC中一樣。

測試

運行客戶端調用服務端來進行測試,發現服務端返回了授權失敗,客戶端同樣獲得了錯誤。這證明我們的服務端配置是沒有問題的

三.客戶端配置

配置

客戶端首先需要從 IdentityServer 申請 Token,然後在調用 gRPC 服務時傳遞過去,這和 HTTP Api 調用一樣。

1.客戶端項目安裝組件 IdentityModel 獲得基於 HttpClient 的和 IdentityServer 的交互的封裝。

2.獲取Token

// discover endpoints from metadata
var client = new HttpClient();

var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
if (disco.IsError)
{
    Console.WriteLine(disco.Error);
    return;
}

// request token
var tokenResponse = await client.RequestPasswordTokenAsync(new PasswordTokenRequest
{
    Address = disco.TokenEndpoint,
    ClientId = "ro.client",
    ClientSecret = "secret",

    UserName = "alice",
    Password = "password",
    Scope = "grpc1"
});

if (tokenResponse.IsError)
{
    Console.WriteLine(tokenResponse.Error);
    return;
}

Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");

3.為 gRPC 客戶端請求設置 Token

和 HTTP Api 調用一樣,gRPC也是放在頭部的

var headers = new Metadata {{"Authorization", $"Bearer {tokenResponse.Json["access_token"]}"}};

var catClient = new LuCat.LuCatClient(channel);
var catReply = await catClient.SuckingCatAsync(new Empty(), headers);

主要就是在調用 SuckingCatAsync方法時,傳入了header。

測試

可以看到成功的進行了調用。

四.結束

本文所用代碼地址:

gRPC in Asp.Net Core :

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

Flutter 構建的 Mac 桌面應用上無法發出網絡?

在上一篇文章中我們分享了,如何開發桌面應用。在本章文章中,來解決一下為何在 Mac 中無法發出網絡情況的原因。

起因

事情​起因是這樣的:我總覺得寫一個 Demo 不足以體現我們開發同學的能力。直到最近,我發現了一個可以改善的小點,可幫助我們的測試同學提高測試效率。

大體情況就是在某天晚上,客戶端的一個小問題,需要進行驗證。但是呢,測試同學要做回歸測試,把所有的數據都重新創建了一遍。但是此過程用了很久,理論來說,應該十來分鐘搞定的事情。我就靜靜的在她身旁看着,內心捉急萬分,畢竟我想早點回家(睡覺,打遊戲,看電視)。最後晚上 11 點多打車回家,一路上我都在想,這個問題應該很快就能驗證好吧,為何要折騰這麼就呢?也許是流程真這麼長吧,那我們無法改變流程,那就做出能提升效率的工具吧。

次日,我把我的想法告訴了她,但是她說我們有自己的網頁工具,可以解決啊,只是現在沒時間創建腳本。隨後我擱置這個想法,但是這種提升效率的想法一直縈繞在我的心頭。

再然後,某天突然意識到,同樣是工具,大家都會使用順手好用的,幹嘛使用哪種傳統老土的工具呢?基於這一點,我開啟了新的探索。

我不僅要做客戶端的,還要做網頁的,更要做桌面應用(測試同學最關注)。我要體驗更好,不僅方便我自己測試,還要給所有的測試同學提供便利,減少加班是我的最終目的,哈哈哈。

想法有了,那就開始實施吧。之前遇到一個問題,一直沒解決,但是此刻必須解決了。那就是之前 Flutter 構建的 Mac 應用后,無法發出網絡請求。

在桌面應用無法發出請求?

添加 Dio 以後,會遇到這種情況:

提示,當前系統不支持該操作。

為何會有如此問題,在 Dio 上支持 Other,也就是支持 Mac ,Windows, Linux, 為何我們直接運行有錯誤呢?

具體原因

實際是因為 Mac 應用有沙箱限制,需要在對應文件中開啟即可。

<key>com.apple.security.network.client</key>
<true/>

添加以後,效果如下:

具體參考: https://github.com/google/flutter-desktop-embedding/issues/546

代碼示例:

import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

// Sets a platform override for desktop to avoid exceptions. See
// https://flutter.dev/desktop#target-platform-override for more info.
void _enablePlatformOverrideForDesktop() {
  if (!kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux)) {
    debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
  }
}

void main() {
  _enablePlatformOverrideForDesktop();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;
  String requestData = "";

  void _incrementCounter() {
    setState(() {
      _counter++;
      getHttp();
    });
  }

  void getHttp() async {
    try {
      Response response = await Dio().get("http://www.gdky005.com");
      requestData = response.toString();
      print(requestData);
    } catch (e) {
      print(e);
      requestData = e.toString();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            Container(
              height: 400,
              child: ListView(
                children: <Widget>[
                  Text(
                    '$requestData',
                  )
                ],
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

小三通物流營運型態?

※快速運回,大陸空運推薦?

奧地利一名果農因違法噴灑殺蟲劑,隸屬鄰近2個養蜂人超過50個蜂群因此死亡

奧地利一名果農因違法噴灑殺蟲劑,隸屬鄰近2個養蜂人超過50個蜂群因此死亡。26日奧地利克拉根福法院(Klagenfurt)以「蓄意危害環境」,判處果農1年有期徒刑,至少需服刑4個月才可假釋,以及賠償超過2萬歐元(2萬3500美元)。

這名47歲果農針對他位於奧地利卡林西亞省(Carinthia)拉萬特地區(Lavanttal)的果樹噴灑藥效強大的殺蟲劑陶斯松(chlorpyrifos),當時果樹的花仍會吸引蜜蜂前去。法院指出,以他的經驗和訓練他人的角色,足以證明他知道自身行為會帶來何種後果。

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

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

球系統科學家Surendra Adhikari表示,研究團隊設計出一套地球自旋物理學電腦模型

球系統科學家Surendra Adhikari表示,研究團隊設計出一套地球自旋物理學電腦模型,加入20世紀大陸冰川(冰蓋)與海水平衡變化的所有數據,終於找出影響地軸飄移至關重要的第2個原因:格陵蘭島冰蓋大量融化。

目前地球上僅存的大陸冰川只剩下南極洲與格陵蘭島,南極冰蓋覆蓋範圍約1,400萬平方公里,隨著20世紀氣溫上升加劇,格陵蘭冰蓋至今已有約7,500億噸的冰融化進入海洋,這導致地球質量分佈發生變化,進而使地軸飄移。一旦南極冰蓋融化,全球海平面將上升61.1公尺;格陵蘭冰蓋則佔據格陵蘭島82%陸地面積,如果格陵蘭冰蓋融化,將導致海平面上升7.2公尺。這項研究明確顯示了人類活動正在改變地球的基本性質及運作方式。

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

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

小三通物流營運型態?

※快速運回,大陸空運推薦?

特斯拉 Model 3 大賣,電動車朝向榮景仍逢瓶頸?

電動車大廠特斯拉(Tesla)新款房車 Model 3 的預購量超出預期,市場上開始有許多分析師發言,有的說電動車即將取代傳統的汽車;有人甚至認為應該忘掉正面臨創新瓶頸的 Apple 執行長 Tim Cook,將目光移向 Tesla 創辦人 Elon Musk,稱他是偉大夢想及實踐家,其能力傲視全球的企業家,然而事實真是如此嗎?   電動車大廠特斯拉(Tesla)新款房車 Model 3 於 2016 年 3 月展開全球預售,售價 3.5 萬美元(約新台幣 110 萬元),買主只需要預付 1,000 美元(約新台幣 3 萬元)就可以訂車,此舉立刻引起市場震撼,吸引大批車迷排隊預購,光是在一天內便湧入 11 萬筆訂單,首周預購就超過 32 萬筆。  
暗藏玄機的預購書   仔細看看 Tesla 的預購合約書(其實這算不上合約書只是預購同意書而已),就可以看出到底為什麼大家會一窩蜂的搶訂。Tesla 的預購條件很簡單,任何人想要訂購 Model 3,只需要支付 1,000 美元的訂金,而且任何時間如果後悔都可以全部退還,換句話說,對消費者而言沒有任何風險;同樣的,Tesla 在文件裡也沒有寫明交車時間,檯面上說 2017 年底是「預定」交車時間,但如果交不出來或延後到 2018 甚至 2020 年,也沒有任何罰則。   放眼望去,哪家車廠會訂出這種購車合約?這樣的操作 Tesla 的目的為何?   Tesla 成立於 2003 年,到現在已經超過 12 年了,它是第一家把電動車成功推到全球市場的公司,讓電動車與高級車畫上等號,吸引到高收入客戶。Tesla 帶給人們對於未來汽車的夢想,進而推升了它的高股價,甚至比大部分賺錢的公司還要高出十幾、二十倍。美國汽車在 2015 年銷售創下歷來最佳紀錄,但福特(Ford)和通用(GM)等汽車業者股票卻大跌,股價本益比僅 5~7 倍,而 Tesla 卻能在持續虧損下,過去 3 年漲了將近 400%,比標普 500 指數與其他傳統車商要好得多。   2013 年 Tesla 進軍中國,希望拿下繼美國之後第二個龐大的電動車市場,甚至 Musk 曾揚言「中國市場很快就超越美國成為 Tesla 電動車的第一大市場」。但是 Tesla 一直無法突破瓶頸,2015 第三季結束的交車總量只有 3,025 輛,不到全球交付量 50,580 輛的十分之一。目前看起來 Tesla 要搶下中國市場,還有一段很漫長的路要走,除了中國政策的問題,無補貼、高關稅、被排除在國家標準之外,各國車廠也紛紛摩拳擦掌,準備搶食中國電動車的市場大餅。   長期的虧損也讓華爾街的分析師對 Musk 的耐心慢慢消磨殆盡,除了進軍中國沒有交出漂亮的成績單,Tesla 還是延遲交貨的慣犯,從首款電動車 Roadster、次代 Model S 到電動休旅車 Model X,從未準時交貨,Model X 甚至還延遲超過一年半。  
先求資金到位以利發展   雖然 Model 3 被定位成平價車款,它的設計沒有其他現有車款 Model S 與 Model X 複雜,但是能不能準時交貨並不是 Tesla 說了算,還是得仰賴後端生產零件的供應商是否如期交貨。Tesla 也預見可能發生的狀況,已先幫自己找替代方案,在加州費利蒙〈Fremont〉的生產工廠自行製造所需零件。   另外電池材料來源與價格,也是必須考量的因素。電動車使用鋰電池做為動力來源,除了電池本身必須非常嚴謹安全,當需求量大增時也會推升鋰材料的價格,因此未必能夠因為數量大幅成長而使價格大幅下降。2015 年第四季開始,就發生鋰電池正極材料所需的碳酸鋰缺貨,導致鋰電池廠商無法擴產,碳酸鋰每噸的市場價格也從 2013 年 9 月的 5 萬人民幣上漲到 12 萬人民幣。Model 3 都還沒做出來碳酸鋰價格就開始上漲了!   大量的電動車充電需求也代表電力基礎建設必須更新,這也不是短時間內可以做到的事,而 Tesla 垂涎欲滴的中國市場,雖然計劃擴建充電站,卻只支援中國國內的電動車品牌。超級充電站不相容、充電難的問題將進一步加劇 Tesla 的困境。   Tesla 可以在一周內拿到超過 30 萬的消費者預購同意書,並不代表真的能做到這麼多生意,連 Musk 都對 2017 年是否能順利上市不太有信心,他在發表會上說「Model 3 不太可能如期交車」。而當 2017 年時間一到,如果交不出令人滿意的 Model 3,或是首購的客戶有了不好的評價,到時候退訂的浪潮也會很兇猛的。   因此 Tesla「不訂出逾期的賠償條款」,對消費者和他們而言可謂雙贏策略。對消費者來說沒有任何風險,還可以過過 Tesla 車主的癮,於是消費者瘋狂訂購;對 Tesla 來說,可以向華爾街的分析師與市場上的投資人證明 Tesla 的潛在客戶非常龐大,有利於向資本市場募資吸金,等於是先拿到了訂單,再回頭過來向市場募資,一箭雙鵰。  
交車不順恐不利後續發展   而 2017 年是否真的能交車呢?是否真的能賣到 3.5 萬美元這麼低的價格?那是以後的事了,只要資金到位,未來要怎麼做都好說;缺少了資金和市場信心,別談以後了,Tesla 可能就要面臨後勢不振的壓力了。   Musk 在資本市場上為投資人,也為新創公司建立一個遠大的夢想並沒有什麼不對,而且手法高明了許多,但 Musk 真的能把 Cook 比下嗎?蘋果一直以來都是腳踏實地在創新,東西真的做得好賣得好,而賺大錢富可敵國才讓股票大漲的,當然做得再好的產品也會遭遇瓶頸,但是這畢竟靠的是腳踏實地的「本益比」,而不是虛幻不實的「本夢比」。   在商場上投機的確是會成功的,有時候成功的機率還不低,但是如果我們過度推崇投機,把投機說成是偉大夢想及實踐能力傲視全球,那對腳踏實地在創新的 Steven Jobs 和 Cook 也太不公平了!   (首圖來源: CC BY 2.0)   (本文授權轉載自《》─〈〉)

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

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

Tesla年產50萬電動車牛皮吹太大,供應商坦承沒把握

特斯拉(Tesla)計畫在2018年大規模量產平價電動車Model 3,時程較原先計畫提早兩年,雖然展現特斯拉執行長穆斯克(Elon Musk)強大企圖心,但也飽受專家質疑,甚至特斯拉旗下供應商對於是否能達成目標也沒把握。   Model 3已開放預定,特斯拉目前累計收到37.3萬輛的訂單、預計2017年底開始交車。但外界所不知道的是,供應商是在三個月之前才被告知增產計畫提前,相關準備作業是否先完成令人質疑。據路透社引述知情人事消息報導指出,特斯拉最新計畫把2017年Model 3產出規模提高兩倍至10萬輛,2018年更將達成40萬輛的產出水平。   穆斯克4月28日曾在財報法說會上對分析師誇下海口,2018年整體產出規模(含Model S、Model X、Model 3)將來到50萬輛,是去年的十倍,也較預設時程快了兩年。不過Model 3設計目前還要等到6月才定案,距初次量產僅剩13個月。   電動車零組件何其多,且缺一不可,特斯拉如何在短時間內搞定供應商、備齊所有零組件,雖然並非完全不可能,但挑戰難度絕對相當高,這也考驗穆斯克的管理協調能力。值得一提的是,北美目前僅有少數汽車產線有年產50萬輛的能力,且背後都有幾十年經驗的車廠在運籌帷幄。   (本文內容由授權使用;首圖來源: CC BY 2.0)

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

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

小三通物流營運型態?

※快速運回,大陸空運推薦?

除了獲取 MAC 地址還能幹啥

        以前寫過一篇《》的文章,文章的地址是:https://www.cnblogs.com/tosser/p/9022187.html,我當時使用 OCX 來實現,可是 OCX 只支持 IE 瀏覽器,後來在往上找了一個 Chrome 的擴展,也解決了該問題。不過,總覺得無論使用 OCX 還是使用 Chrome 的擴展,都是瀏覽器相關的,並不通用。後來,使用 Socket 寫了一個簡單的 DEMO,用來模擬 HTTP 服務器,然後使用 Ajax 進行通信,問題解決了。也不再是瀏覽器相關了。

 

Web 頁面獲取 MAC 地址的設計思路

        Web 頁面獲取 MAC 地址的設計思路是比較簡單的,只需要在本地模擬一個 HTTP 服務器,然後讓 Web 頁面通過 Ajax 來請求 HTTP 服務器,HTTP 服務器直接返回本機的 MAC 地址就可以了。

        具體流程如下圖:

 

        流程圖非常的清楚,主要就是 HostServer 和 Ajax 的通信,這樣就可以得到 MAC 地址,然後通過 DOM 操作,即可把 MAC 地址寫入到 input 框中。這樣,就可以和用戶名、密碼一起提交給服務器進行驗證了。

 

 

 

除了獲取 MAC 地址還能幹啥

 

       之前做過一個物流提貨的項目,涉及到一些硬件設備,包括:小票打印機、刷卡器(身份證、銀聯卡)、進幣器、密碼数字鍵盤等。這些設備、電腦主機和显示器在一個類似 ATM 機那樣的機櫃中(其實就是 ATM 機的設備,本身這套東西就是銀行提供的)。

 

       操作這些硬件的接口廠家提供了一個 OCX,而整個項目是 B/S 架構的。那麼,在客戶端想要操作這些硬件,就要調用 OCX,而 OCX 只能在 IE 瀏覽器下使用(Chrome、FireFox 是不支持 OCX 的)。眾所周知,IE 對 Web 並不友好,但是如何又能在不使用 IE 的情況下,又去調用 OCX 來完成操作硬件的功能呢?那麼就是我們上面的方法了。

 

       簡單的描述一下,就不貼圖了。

 

       在終端上放一個 HostServer 用來接受頁面中 Ajax 的請求,並根據請求去調用 OCX 中相應的功能,把 OCX 的返回信息,再以 Json 的格式返回給 Ajax 即可。

 

       這樣,把 瀏覽器 和 OCX 文件進行了分離,中間加入了一個 HostServer,頁面 和 OCX 的通信通過了 HostServer,那麼以後如果接口是 DLL 文件,也可以通過 HostServer 來進行完成,當然,還可以完成更多的功能。

 

 

 

總結

        其實整個獲取 MAC 地址的功能,對於登錄頁面而言是一個服務端,它在本地是一個可執行的程序,那麼它和普通的 EXE 文件是沒有區別的,那麼它能完成的功能其實遠遠不是獲取一個 MAC 地址的功能,對於上面的例子來說,把服務的提供者和使用者進行了分離,而且針對於本機的擴展也十分的方便了。當然,如果你願意的話,可以讓 HostServer 充當客戶端直接和後端的服務器進行通信而不通過瀏覽器,這樣是不是還能做一些讓用戶沒有感知的事情?

 

 

我的微信公眾號:“碼農UP2U”

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

asp.net core 自定義 Policy 替換 AllowAnonymous 的行為

asp.net core 自定義 Policy 替換 AllowAnonymous 的行為

Intro

最近對我們的服務進行了改造,原本內部服務在內部可以匿名調用,現在增加了限制,通過 identity server 來管理 api 和 client,網關和需要訪問api的客戶端或api服務相互調用通過 client_credencial 的方式來調用,這樣一來我們可以清晰知道哪些 api 服務會被哪些 api/client 所調用,而且安全性來說更好。
為了保持後端服務的代碼更好的兼容性,希望能夠實現相同的代碼通過在 Startup 里不同的配置實現不同的 Authorization 邏輯,原來我們的服務的 Authorize 都是以 Authorize("policyName") 的形式來寫的,這樣一來我們只需要修改這個 Policy 的授權配置就可以了。對於 AllowAnonymous 就希望可以通過一種類似的方式來實現,通過自定義一個 Policy 來實現自己的邏輯

實現方式

將 action 上的 AllowAnonymous 替換為 Authorize("policyName"),在沒有設置 Authorize 的 controller 上增加 Authorize("policyName")

public class AllowAnonymousPolicyTransformer : IApplicationModelConvention
{
    private readonly string _policyName;

    public AllowAnonymousPolicyTransformer() : this("anonymous")
    {
    }

    public AllowAnonymousPolicyTransformer(string policyName) => _policyName = policyName;

    public void Apply(ApplicationModel application)
    {
        foreach (var controllerModel in application.Controllers)
        {
            if (controllerModel.Filters.Any(_ => _.GetType() == typeof(AuthorizeFilter)))
            {
                foreach (var actionModel in controllerModel.Actions)
                {
                    if (actionModel.Filters.Any(_ => _.GetType() == typeof(AllowAnonymousFilter)))
                    {
                        var allowAnonymousFilter = actionModel.Filters.First(_ => _.GetType() == typeof(AllowAnonymousFilter));
                        actionModel.Filters.Remove(allowAnonymousFilter);
                        actionModel.Filters.Add(new AuthorizeFilter(_policyName));
                    }
                }
            }
            else
            {
                if (controllerModel.Filters.Any(_ => _.GetType() == typeof(AllowAnonymousFilter)))
                {
                    var allowAnonymousFilter = controllerModel.Filters.First(_ => _.GetType() == typeof(AllowAnonymousFilter));
                    controllerModel.Filters.Remove(allowAnonymousFilter);
                }
                controllerModel.Filters.Add(new AuthorizeFilter(_policyName));
            }
        }
    }
}

public static class MvcBuilderExtensions
{
    public static IMvcBuilder AddAnonymousPolicyTransformer(this IMvcBuilder builder)
    {
        builder.Services.Configure<MvcOptions>(options =>
        {
            options.Conventions.Insert(0, new AllowAnonymousPolicyTransformer());
        });
        return builder;
    }

    public static IMvcBuilder AddAnonymousPolicyTransformer(this IMvcBuilder builder, string policyName)
    {
        builder.Services.Configure<MvcOptions>(options =>
        {
            options.Conventions.Insert(0, new AllowAnonymousPolicyTransformer(policyName));
        });
        return builder;
    }
}

controller 中的代碼:

[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly ILogger _logger;

    public ValuesController(ILogger<ValuesController> logger)
    {
        _logger = logger;
    }

    // GET api/values
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        var msg = $"IsAuthenticated: {User.Identity.IsAuthenticated} ,UserName: {User.Identity.Name}";
        _logger.LogInformation(msg);
        return new string[] { msg };
    }

    // GET api/values/5
    [Authorize]
    [HttpGet("{id:int}")]
    public ActionResult<string> Get(int id)
    {
        return "value";
    }
    // ...
}

Startup 中 ConfigureServices 配置:

var anonymousPolicyName = "anonymous";

services.AddAuthorization(options =>
{
    options.AddPolicy(anonymousPolicyName, builder => builder.RequireAssertion(context => context.User.Identity.IsAuthenticated));

    options.DefaultPolicy = new AuthorizationPolicyBuilder(HeaderAuthenticationDefaults.AuthenticationSchema)
        .RequireAuthenticatedUser()
        .RequireAssertion(context => context.User.GetUserId<int>() > 0)
        .Build();
});

services.AddMvc(options =>
    {
        options.Conventions.Add(new ApiControllerVersionConvention());
    })
    .AddAnonymousPolicyTransformer(anonymousPolicyName)
    ;

實現效果

訪問原來的匿名接口

userId 為0訪問原來的匿名接口

userId 大於0訪問原來的匿名接口

userId 為0訪問需要登錄的接口

userId 大於0訪問需要登錄的接口

More

注:按照上面的做法已經可以做到自定義 policy 代替 AllowAnonymous 的行為,但是原來返回的401,現在可能返回到就是 403 了

Reference

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

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

jwt 實踐應用以及特殊案例思考

2{icon} {views}

JSON Web Token 是 出的一份標準,使用 JSON 來傳遞數據,用於判定用戶是否登錄狀態。

jwt 之前,使用 session 來做用戶認證。

以下代碼均使用 javascript 編寫。

  • 原文鏈接:

session

傳統判斷是否登錄的方式是使用 session + token

token 是指在客戶端使用 token 作為用戶狀態憑證,瀏覽器一般存儲在 localStorage 或者 cookie 中。

session 是指在服務器端使用 redis 或者 sql 類數據庫,存儲 user_id 以及 token 的鍵值對關係,基本工作原理如下。

在服務器端使用 sessions 存儲鍵值對

const sessions = {
  "ABCED1": 10086,
  "CDEFA0": 10010
}

每次客戶端請求帶權限數據時攜帶 token,在服務器端根據 token 與 sessions 獲取 user_id, 完成認證過程

function getUserIdByToken (token) {
  return sessions[token]
}

如果存儲在 cookie 中就是經常聽到的 session + cookie 的登錄方案。其實存儲在 cookielocalStorage 甚至 IndexedDB 或者 WebSQL 各有利弊,核心思想一致。

關於 cookie 以及 token 優缺點,在 中有討論。

如果不使用 cookie,可以採取 localStorage + Authorization 的方式進行認證,更加無狀態化

// http 的頭,每次請求權限接口時,需要攜帶 Authorization Header
const headers = {
  Authorization: `Bearer ${localStorage.get('token')}`
}

推薦一個前端的存儲庫 ,使用 IndexedDBWebSQL 以及 IndexedDB 做鍵值對存儲。

無狀態登錄

session 需要在數據庫中保持用戶及token對應信息,所以叫 有狀態

試想一下,如何在數據庫中不保持用戶狀態也可以登錄。

第一種方法: 前端直接傳 user_id 給服務端

缺點也特別特別明顯,容易被用戶篡改成任意 user_id,權限設置形同虛設。不過思路正確,接着往下走。

改進: 對 user_id 進行對稱加密

服務端對 user_id 進行對稱加密后,作為 token 返回客戶端,作為用戶狀態憑證。比上邊略微強點,但由於對稱加密,選擇合適的算法以及密鑰比較重要

改進: 對 user_id 不需要加密,只需要進行簽名,保證不被篡改

這便是 jwt 的思想:user_id,加密算法和簽名組成 token 一起存儲到客戶端,每當客戶端請求接口時攜帶 token,服務器根據 token 解析出加密算法與 user_id 來判斷簽名是否一致。

Json Web Token

jwt 根據 HeaderPayload 以及 Signature 三個部分由 . 拼接而成。

Header

Header 由非對稱加密算法和類型組成,如下

const header = {
  // 加密算法
  alg: 'HS256',
  type: 'jwt'
}

Payload

Payload 中由 以及需要通信的數據組成。這些數據字段也叫 Claim

Registered Claim 中比較重要的是 "exp" Claim 表示過期時間,在用戶登錄時會設置過期時間。

const payload = {
  // 表示 jwt 創建時間
  iat: 1532135735,

  // 表示 jwt 過期時間
  exp: 1532136735,

  // 用戶 id,用以通信
  user_id: 10086
}

Signature

SignatureHeaderPayload 以及 secretOrPrivateKey 計算而成。secretOrPrivateKey 作為敏感數據存儲在服務器端,可以考慮使用 vault secret 或者 k8s secret

對於 secretOrPrivateKey,如果加密算法採用 HMAC,則為字符串,如果採用 RSA 或者 ECDSA,則為 PrivateKey。

// 由 HMACSHA256 算法進行簽名,secret 不能外泄
const sign = HMACSHA256(base64.encode(header) + '.' + base64.encode(payload), secret)

// jwt 由三部分拼接而成
const jwt = base64.encode(header) + '.' + base64.encode(payload) + '.' + sign

從生成 jwt 規則可知客戶端可以解析出 payload,因此不要在 payload 中攜帶敏感數據,比如用戶密碼

校驗過程

在生成規則中可知,jwt 前兩部分是對 header 以及 payload 的 base64 編碼。

當服務器收到客戶端的 token 后,解析前兩部分得到 header 以及 payload,並使用 header 中的算法與 secretOrPrivateKey 進行簽名,判斷與 jwt 中攜帶的簽名是否一致。

帶個問題,如何判斷 token 過期?

應用

由上可知,jwt 並不對數據進行加密,而是對數據進行簽名,保證不被篡改。除了在登錄中可以用到,在進行郵箱校驗,圖形驗證碼和短信驗證碼時也可以用到。

圖形驗證碼

在登錄時,輸入密碼錯誤次數過多會出現圖形驗證碼。

圖形驗證碼的原理是給客戶端一個圖形,並且在服務器端保存與這個圖片配對的字符串,以前也大都通過 session 來實現。

可以把驗證碼配對的字符串作為 secret,進行無狀態校驗。

const jwt = require('jsonwebtoken')

// 假設驗證碼為字符驗證碼,字符為 ACDE,10分鐘失效
const token = jwt.sign({}, secrect + 'ACDE', { expiresIn: 60 * 10 })

const codeImage = getImageFromString('ACDE')

// 給前端的響應
const res = {
  // 驗證碼圖片的 token,從中可以校驗前端發送的驗證碼
  token,
  // 驗證碼圖片
  codeImage,
}

短信驗證碼與圖形驗證碼同理

郵箱校驗

現在網站在註冊成功後會進行郵箱校驗,具體做法是給郵箱發一個鏈接,用戶點開鏈接校驗成功。

// 把郵箱以及用戶id綁定在一起
const code = jwt.sign({ email, userId }, secret, { expiresIn: 60 * 30 })

// 在此鏈接校驗驗證碼
const link = `https://example.com/code=${code}`

無狀態 VS 有狀態

關於無狀態和有狀態,在其它技術方向也有對比,比如 React 的 stateLess component 以及 stateful component,函數式編程中的副作用可以理解為狀態,http 也是一個無狀態協議,需要靠 header 以及 cookie 攜帶狀態。

在用戶認證這裏,有無狀態是指是否依賴外部數據存儲,如 mysql,redis 等。

案例

思考以下幾個關於登錄的問題如何使用 session 以及 jwt 實現,來更加清楚 jwt 的使用場景

當用戶註銷時,如何使該 token 失效

因為 jwt 無狀態,不保存用戶設備信息,沒法單純使用它完成以上問題,可以再利用數據庫保存一些狀態完成。

  • session: 只需要把 user_id 對應的 token 清掉即可
  • jwt: 使用 redis,維護一張黑名單,用戶註銷時把該 token 加入黑名單,過期時間與 jwt 的過期時間保持一致。

如何允許用戶只能在一個設備登錄,如微信

  • session: 使用 sql 類數據庫,對用戶數據庫表添加 token 字段並加索引,每次登陸重置 token 字段,每次請求需要權限接口時,根據 token 查找 user_id
  • jwt: 假使使用 sql 類數據庫,對用戶數據庫表添加 token 字段(不需要添加索引),每次登陸重置 token 字段,每次請求需要權限接口時,根據 jwt 獲取 user_id,根據 user_id 查用戶表獲取 token 判斷 token 是否一致。另外也可以使用計數器的方法,如下一個問題。

對於這個需求,session 稍微簡單些,畢竟 jwt 也需要依賴數據庫。

如何允許用戶只能在最近五個設備登錄,如諸多播放器

  • session: 使用 sql 類數據庫,創建 token 數據庫表,有 id, token, user_id 三個字段,user 與 token 表為 1:m 關係。每次登錄添加一行記錄。根據 token 獲取 user_id,再根據 user_id 獲取該用戶有多少設備登錄,超過 5 個,則刪除最小 id 一行。
  • jwt: 使用計數器,使用 sql 類數據庫,在用戶表中添加字段 count,默認值為 0,每次登錄 count 字段自增1,每次登錄創建的 jwt 的 Payload 中攜帶數據 current_count 為用戶的 count 值。每次請求權限接口時,根據 jwt 獲取 count 以及 current_count,根據 user_id 查用戶表獲取 count,判斷與 current_count 差值是否小於 5

對於這個需求,jwt 略簡單些,而使用 session 還需要多維護一張 token 表。

如何允許用戶只能在最近五個設備登錄,而且使某一用戶踢掉除現有設備外的其它所有設備,如諸多播放器

  • session: 在上一個問題的基礎上,刪掉該設備以外其它所有的token記錄。
  • jwt: 在上一個問題的基礎上,對 count + 5,並對該設備重新賦值為新的 count。

如何显示該用戶登錄設備列表 / 如何踢掉特定用戶

  • session: 在 token 表中新加列 device
  • jwt: 需要服務器端保持設備列表信息,做法與 session 一樣,使用 jwt 意義不大

總結

從以上問題得知,如果不需要控制登錄設備數量以及設備信息,無狀態的 jwt 是一個不錯的選擇。一旦涉及到了設備信息,就需要對 jwt 添加額外的狀態支持,增加了認證的複雜度,此時選用 session 是一個不錯的選擇。

jwt 不是萬能的,是否採用 jwt,需要根據業務需求來確定。

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

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

小三通物流營運型態?

※快速運回,大陸空運推薦?