[全域] Jwt token 經過 base 刷新 token 程序 | GetAlarm 原本從資料庫取得警報改成從 Niagara Obix 方式取得資料

This commit is contained in:
dev01 2023-09-20 17:32:03 +08:00
parent 5931e057b0
commit 343681e1f1
10 changed files with 347 additions and 144 deletions

View File

@ -0,0 +1,158 @@
using FrontendWebApi.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using Repository.FrontendRepository.Interface;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
namespace FrontendWebApi.ApiControllers
{
/// <summary>
/// 告警紀錄
/// </summary>
public class AlarmController : MyBaseApiController<AlarmRecordController>
{
private readonly IFrontendRepository frontendRepository;
public AlarmController
(
IFrontendRepository frontendRepository
)
{
this.frontendRepository = frontendRepository;
}
[HttpPost]
[Route("api/Alarm/GetAlarmFromObix")]
public async Task<ActionResult<ApiResult<AlarmObj>>> GetAlarmFromObix()
{
ApiResult<AlarmObj> apiResult = new ApiResult<AlarmObj>(jwt_str);
if (!jwtlife)
{
apiResult.Code = "5000";
return BadRequest(apiResult);
}
try
{
var sqlString = $@"SELECT system_value FROM variable WHERE system_type = 'obixConfig' AND system_key = 'ApiBase' AND deleted = 0";
string baseApiUrl = await frontendRepository.GetOneAsync<string>(sqlString);
if (string.IsNullOrEmpty(baseApiUrl))
{
apiResult.Code = "9998";
apiResult.Msg = "未找到 obixConfig baseAPI請聯絡管理者。";
return BadRequest(apiResult);
}
string apiUrl = Path.Combine(baseApiUrl, "obix/config/Services/AlarmService/~alarmQuery/");
using (HttpClient client = new HttpClient())
{
string username = "stanGG";
string password = "St12345678";
string encoded = Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
client.DefaultRequestHeaders.Add("Authorization", "Basic " + encoded);
// 建構 XML 數據
string xmlData = @$"<obj href='obix:AlarmFilter'>
<abstime name='start' val='{DateTime.Now.AddDays(-180).ToString("yyyy-MM-ddTHH:mm:ss.fff")}+08:00' />
<abstime name='end' val='{DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fff")}+08:00'/>
</obj>";
HttpContent content = new StringContent(xmlData, Encoding.UTF8, "application/xml");
var response = await client.PostAsync(apiUrl, content);
var resString = (await response.Content.ReadAsStringAsync()).ToString();
XDocument xmlDoc = XDocument.Parse(resString);
/*
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type='text/xsl' href='/obix/xsl'?>
<obj is="obix:AlarmQueryOut" xmlns="http://obix.org/ns/schema/1.0" xsi:schemaLocation="http://obix.org/ns/schema/1.0 /obix/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<list name="data" of="obix:Alarm">
<obj href="/obix/alarm/3378ed4a-94ff-4aca-b857-ff66083b9131" is="obix:Alarm obix:AckAlarm obix:PointAlarm obix:StatefulAlarm" display="">
....
<str name="sourceName" val="H_E1_B1F_MVCB_MVCBH_ER"/>
<abstime name="timestamp" val="2023-08-08T10:30:04.473+08:00" tz="Asia/Taipei"/>
....
</obj>
<obj href="/obix/alarm/f6116713-9830-4e7d-aa10-a28db29d0edc" is="obix:Alarm obix:AckAlarm obix:PointAlarm obix:StatefulAlarm" display="">
....
<str name="sourceName" val="H_E1_B1F_MVCB_MVCBH_ER"/>
<abstime name="timestamp" val="2023-08-08T10:50:00.953+08:00" tz="Asia/Taipei"/>
....
</obj>
</list>
</obj>
*/
var list = xmlDoc.Descendants().Where(d => d.Name?.LocalName == "list").FirstOrDefault();
var objs = list.Descendants().Where(d => d.Name?.LocalName == "obj" && (d.Attribute("is")?.Value?.Contains("obix:Alarm") ?? false)).ToList();
// 宣告要丟出去的資料容器
AlarmObj alarmObj = new AlarmObj()
{
alarmorion = new List<AlarmorionString>(),
buildingAlarmDeviceAmount = new List<BuildingAlarmDeviceAmount>()
};
// 篩選 toState != normal
objs = objs.Where(d => d.Descendants().Any(dd => dd?.Name?.LocalName == "str" && dd?.Attribute("name")?.Value == "toState" && dd?.Attribute("val")?.Value != "normal")).ToList();
// <str name="sourceName" val="H_E1_B1F_MVCB_MVCBH_ER"/>
// <abstime name="timestamp" val="2023-08-08T10:30:04.473+08:00" tz="Asia/Taipei"/>
alarmObj.alarmorion = objs.Select(obj => new AlarmorionString()
{
alarm_timestamp = obj.Descendants().Where(d => d.Name.LocalName == "abstime" && d.Attribute("name").Value == "timestamp")
.Select(d =>
{
DateTime valid;
if (DateTime.TryParse(d.Attribute("val").Value, out valid))
{
return DateTime.Parse(d.Attribute("val").Value).ToString("yyyy-MM-dd HH:mm:ss.fff");
}
else
{
return null;
}
}).FirstOrDefault(),
device_number = obj.Descendants().Where(d => d.Name.LocalName == "str" && d.Attribute("name").Value == "sourceName")
.Select(d => d.Attribute("val").Value).Select(d => string.Join("_", d.Split("_").Take(5))).FirstOrDefault(),
}).ToList();
// obix alarm 回傳 device_number + point 取出棟別分組
alarmObj.buildingAlarmDeviceAmount = alarmObj.alarmorion.Where(a => a.device_number?.Contains("_") ?? false)
.GroupBy(g => g.device_number.Split("_")[0]).Select(g => new BuildingAlarmDeviceAmount()
{
building_tag = g.Key,
device_amount = g.Count()
}).ToList();
apiResult.Data = alarmObj;
}
apiResult.Msg = "讀取成功";
apiResult.Code = "0000";
}
catch (Exception exception)
{
apiResult.Code = "9999";
apiResult.Msg = "系統內部錯誤,請聯絡管理者。";
Logger.LogError("【" + controllerName + "/" + actionName + "】" + exception.Message);
return Ok(apiResult);
}
return Ok(apiResult);
}
}
}

View File

@ -17,6 +17,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Net; using System.Net;
using Newtonsoft.Json;
namespace FrontendWebApi.ApiControllers namespace FrontendWebApi.ApiControllers
{ {
@ -58,16 +59,17 @@ namespace FrontendWebApi.ApiControllers
userinfo_guid = User.Claims.Where(a => a.Type == "userinfo_guid").Select(e => e.Value).FirstOrDefault(), userinfo_guid = User.Claims.Where(a => a.Type == "userinfo_guid").Select(e => e.Value).FirstOrDefault(),
}; };
if (myUser.exp == 0) Logger.LogError("MyBaseApi - 61 : " + JsonConvert.SerializeObject(myUser) + "---" + DateTime.Now.AddHours(-8).AddMinutes(10).Subtract(new DateTime(1970, 1, 1)).TotalSeconds);
{
jwt_str = "Jwt Token不合法"; //if (myUser.exp == 0)
jwtlife = false; //{
filterContext.Result = new JsonResult(new { HttpStatusCode.Unauthorized }); // jwt_str = "Jwt Token不合法";
} // jwtlife = false;
else // filterContext.Result = new JsonResult(new { HttpStatusCode.Unauthorized });
{ //}
if (myUser.exp <= DateTime.Now.AddHours(-8).AddMinutes(10).Subtract(new DateTime(1970, 1, 1)).TotalSeconds)
{ //if (myUser.exp <= DateTime.Now.AddHours(-8).AddMinutes(10).Subtract(new DateTime(1970, 1, 1)).TotalSeconds)
//{
jwtlife = true; jwtlife = true;
JwtLogin jwtLoing = new JwtLogin() JwtLogin jwtLoing = new JwtLogin()
{ {
@ -77,20 +79,9 @@ namespace FrontendWebApi.ApiControllers
userinfo_guid = myUser.userinfo_guid userinfo_guid = myUser.userinfo_guid
}; };
jwt_str = jwt.GenerateToken(jwtLoing).token; jwt_str = jwt.GenerateToken(jwtLoing).token;
} //}
}
if (myUser.exp <= DateTime.Now.AddHours(-8).AddMinutes(10).Subtract(new DateTime(1970, 1, 1)).TotalSeconds) Logger.LogError("MyBaseApi - 98 : " + JsonConvert.SerializeObject(myUser));
{
jwtlife = true;
JwtLogin jwtLoing = new JwtLogin()
{
account = "webUser",
email = "webUser@gmail.com",
full_name = "webUser",
userinfo_guid = "6ac24708-3a40-4199-88c5-22df310cd1a8"
};
jwt_str = jwt.GenerateToken(jwtLoing).token;
}
base.OnActionExecuting(filterContext); base.OnActionExecuting(filterContext);
} }
} }

View File

@ -93,7 +93,6 @@ namespace FrontendWebApi.ApiControllers
XDocument xmlDoc = XDocument.Parse(resString); XDocument xmlDoc = XDocument.Parse(resString);
Logger.LogError("【" + controllerName + "/" + actionName + "】" + JsonConvert.SerializeXNode(xmlDoc));
if (xmlDoc?.Root?.Name?.LocalName == "str") if (xmlDoc?.Root?.Name?.LocalName == "str")
{ {
result.targetValue = xmlDoc.Root.Attribute("val").Value; result.targetValue = xmlDoc.Root.Attribute("val").Value;

View File

@ -83,7 +83,6 @@ namespace FrontendWebApi.Controllers
myUserInfo.ShowView = showview.Result; myUserInfo.ShowView = showview.Result;
ViewBag.myUserInfo = myUserInfo; ViewBag.myUserInfo = myUserInfo;
ViewBag.role = showview.Result; ViewBag.role = showview.Result;
ViewBag.WarningValuePxPath = GetWarningValuePxPath().Result;
//var showviewt = new List<string>() //var showviewt = new List<string>()
@ -165,15 +164,5 @@ namespace FrontendWebApi.Controllers
base.OnActionExecuting(filterContext); base.OnActionExecuting(filterContext);
} }
public async Task<string> GetWarningValuePxPath() {
var pxPath = await frontendRepository.GetOneAsync<string>($@"
SELECT system_value FROM `variable` where system_type = 'pxPath' and system_key = 'warningValue' and deleted = '0'");
var frontendPath = await frontendRepository.GetOneAsync<string>($@"
SELECT system_value FROM `variable` where system_type = 'obixConfig' and system_key = 'ApiBase' and deleted = '0'");
pxPath = frontendPath + pxPath;
return pxPath;
}
} }
} }

View File

@ -61,8 +61,8 @@ namespace FrontendWebApi.Jwt
// https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater // https://stackoverflow.com/questions/47279947/idx10603-the-algorithm-hs256-requires-the-securitykey-keysize-to-be-greater
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature); var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var now = DateTime.Now; var now = DateTime.UtcNow;
var expires = DateTime.Now.AddSeconds(lifeseconds); var expires = DateTime.UtcNow.AddSeconds(lifeseconds);
// 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式) // 產出所需要的 JWT securityToken 物件,並取得序列化後的 Token 結果(字串格式)
var tokenHandler = new JwtSecurityTokenHandler(); var tokenHandler = new JwtSecurityTokenHandler();

View File

@ -0,0 +1,17 @@
using NPOI.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace FrontendWebApi.Models
{
public class AlarmObixResult
{
public string alarm_timestamp { get; set; }
public string device_number { get; set; }
public List<BuildingAlarmDeviceAmount> buildingAlarmDeviceAmount { get; set; } = new List<BuildingAlarmDeviceAmount>();
}
}

View File

@ -199,7 +199,7 @@ namespace FrontendWebApi.Models
public class BuildingAlarmDeviceAmount public class BuildingAlarmDeviceAmount
{ {
public string building_guid { get; set; } public string building_tag { get; set; }
public int device_amount { get; set; } public int device_amount { get; set; }
} }

View File

@ -365,26 +365,15 @@
if (!enable_alarm_timer) { if (!enable_alarm_timer) {
return; return;
} }
var url = "/api/Device/Getalarm";
$.post(url, null, function (rel) {
if (rel.code != "0000") {
if (rel.code == "9999") {
toast_error(rel.msg);
}
else {
toast_warning(rel.msg);
}
return;
}
else {
GetAlarmFromObix((data) => {
var is_diff = false; var is_diff = false;
if (Object.keys(temp_alarm_device).length == Object.keys(rel.data.alarmorion).length) { if (Object.keys(temp_alarm_device).length == Object.keys(data.alarmorion).length) {
for (var i = 0; i < Object.keys(rel.data.alarmorion).length; i++) { for (var i = 0; i < Object.keys(data.alarmorion).length; i++) {
var index = temp_alarm_device.findIndex(x => x.alarm_timestamp == rel.data.alarmorion[i].alarm_timestamp var index = temp_alarm_device.findIndex(x => x.alarm_timestamp == data.alarmorion[i].alarm_timestamp
&& x.device_number == rel.data.alarmorion[i].device_number) && x.device_number == data.alarmorion[i].device_number)
if (index > -1) { if (index > -1) {
is_diff = false; is_diff = false;
@ -397,19 +386,20 @@
is_diff = true; is_diff = true;
} }
temp_alarm_device = rel.data.alarmorion; temp_alarm_device = data.alarmorion;
if (show_mode == "alarm" && (is_need_reload || is_diff)) { if (show_mode == "alarm" && (is_need_reload || is_diff)) {
enable_alarm_timer = false; //關閉查詢異常設備,避免重複呼叫 enable_alarm_timer = false; //關閉查詢異常設備,避免重複呼叫
$("#building").find(".building_device_amount").html(0); $("#building").find(".building_device_amount").html(0);
rel.data.buildingAlarmDeviceAmount.forEach(function (item) { data.buildingAlarmDeviceAmount.forEach(function (item) {
$(`#${item.building_tag}_device_amount`).html(item.device_amount); $(`#${item.building_tag}_device_amount`).html(item.device_amount);
}); });
ResetDeviceTable(); ResetDeviceTable();
} }
} })
}, 'json');
}, 3000); }, 3000);
//#endregion //#endregion
@ -643,6 +633,7 @@
data = rel.data; data = rel.data;
try {
if (data == null || data.length == 0) { if (data == null || data.length == 0) {
this.data = []; this.data = [];
is_need_reload = true; is_need_reload = true;
@ -728,6 +719,13 @@
data = alarm_data; data = alarm_data;
} }
}
catch(e) {
console.error(e);
return [];
}
return data; return data;
} }
@ -849,6 +847,27 @@
}); });
//#endregion //#endregion
function GetAlarmFromObix(callback = null){
let url = "/api/Alarm/GetAlarmFromObix"
$.ajax({
url: url,
data: null,
type: 'POST',
dataType: 'json',
success: function (rel) {
if(rel && rel.code == "0000") {
console.log(rel);
callback ? callback(rel.data ?? []) : "";
} else {
toast_error(rel?.msg || "取得警報發生錯誤,請通知資訊相關人員。");
}
},
});
}
//#region 變更查詢內容 //#region 變更查詢內容
function ChangeMode(mode, e) { function ChangeMode(mode, e) {
$('#show-mode').find('button').removeClass('btn-success').addClass('btn-secondary'); $('#show-mode').find('button').removeClass('btn-success').addClass('btn-secondary');

View File

@ -78,7 +78,10 @@
async: false, async: false,
dataType: 'json', dataType: 'json',
success: function (rel) { success: function (rel) {
window.location = "/EmergencyDeviceMenu"; window.location = "/EmergencyDeviceMenu";
}, },
error: function (xhr, textStatus, thrownError) { error: function (xhr, textStatus, thrownError) {
alert(textStatus); alert(textStatus);

View File

@ -883,7 +883,7 @@
</tr> </tr>
<tr> <tr>
<td colspan="2">24小時累積雨量達80毫米以上或時雨量達40毫米以上之降雨現象</td> <td colspan="2" id="rainDesc">24小時累積雨量達80毫米以上或時雨量達40毫米以上之降雨現象</td>
</tr> </tr>
<tr class="disaster-title-bar"> <tr class="disaster-title-bar">
<td rowspan="3" class="disaster-icon"><i class="fa-solid fa-house-chimney-crack"></i></td> <td rowspan="3" class="disaster-icon"><i class="fa-solid fa-house-chimney-crack"></i></td>
@ -915,7 +915,7 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<td colspan="2">幾乎所有家俱都大幅移動或翻倒,部分耐震較強建築物可能損壞或倒塌。</td> <td colspan="2" id="eqDesc">幾乎所有家俱都大幅移動或翻倒,部分耐震較強建築物可能損壞或倒塌。</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -936,6 +936,7 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script> <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation/dist/additional-methods.min.js"></script> <script src="~/lib/jquery-validation/dist/additional-methods.min.js"></script>
<script src="~/lib/jquery-validation/dist/localization/messages_zh_TW.js"></script> <script src="~/lib/jquery-validation/dist/localization/messages_zh_TW.js"></script>
<!-- dataTables --> <!-- dataTables -->
<script src="~/js/datagrid/datatables/datatables.bundle.js"></script> <script src="~/js/datagrid/datatables/datatables.bundle.js"></script>
<!-- SweetAlert --> <!-- SweetAlert -->
@ -981,6 +982,32 @@
$("body").on("show.bs.modal","#warning-value-modal",getWarningValue); $("body").on("show.bs.modal","#warning-value-modal",getWarningValue);
$("body").on("change","input[name=rainRadio]",onRainRadioChange);
$("body").on("change","input[name=eqRadio]",onEqRadioChange);
function onRainRadioChange(e) {
let rainDecDict = {
1:"24小時累積雨量達80毫米以上或時雨量達40毫米以上之降雨現象。",
2:"24小時累積雨量達200毫米以上或3小時累積雨量達100毫米以上之降雨現象。",
3:"24小時累積雨量達350毫米以上之降雨現象。",
4:"24小時累積雨量達500毫米以上之降雨現象。",
};
$("#rainDesc").text(rainDecDict[e.target.value] || "");
}
function onEqRadioChange(){
let eqDecDict = {
3:"房屋震動,碗盤門窗發出聲音,懸掛物搖擺。",
4:"房屋搖動甚烈,少數未固定物品可能傾倒掉落,少數傢俱移動,可能有輕微災害。",
5:"部分未固定物品傾倒掉落,少數傢俱可能移動或翻倒,少數門窗可能變形,部分牆壁產生裂痕。",
6:"大量傢俱大幅移動或翻倒,門窗扭曲變形,部分耐震能力較差房屋可能損壞或倒塌。",
7:"幾乎所有傢俱都大幅移動或翻倒,部分耐震較強建築物可能損壞或倒塌。",
}
$("#eqDesc").text(eqDecDict[e.target.value] || "");
}
function getWarningValue(){ function getWarningValue(){
let url = "api/WarningValue/GetWarningValue"; let url = "api/WarningValue/GetWarningValue";