auth.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. use axum::{extract::{Query, State}, response::Redirect};
  2. use crate::{AppState, datasource::Datasource, log, LogLevel::*};
  3. use serde::Deserialize;
  4. const APPID: &str = "wx664469117500d259";
  5. const APPSECRET : &str = "11ec6e6d4b9062f00a4fc08c529293be";
  6. // const APPSECRET : &str = "wx664469117500d259";
  7. #[derive(serde::Deserialize)]
  8. pub struct QueryParams {
  9. code: String,
  10. state: String,
  11. }
  12. #[allow(dead_code)]
  13. #[derive(Deserialize)]
  14. pub struct WxGetToken{
  15. access_token: String,
  16. expires_in: usize,
  17. refresh_token: String,
  18. openid: String,
  19. scope:String
  20. }
  21. /*
  22. https://open.weixin.qq.com/connect/oauth2/authorize?appid=
  23. &redirect_uri=http://192.168.24.101:3000/auth&response_type=code&scope=snsapi_base&state=1#wechat_redirect
  24. wx664469117500d259
  25. wxdf57fde70a442828
  26. */
  27. #[allow(dead_code)]
  28. #[derive(Deserialize)]
  29. pub struct WxUserInfo{
  30. openid: String,
  31. nickname: String,
  32. sex: u16,
  33. headimgurl: String,
  34. }
  35. pub async fn auth(
  36. // headers: HeaderMap,
  37. State(state): State<AppState>,
  38. Query(q): Query<QueryParams>
  39. ) -> Redirect {
  40. /*
  41. 从公众号跳转时会访问 http://{{host}}/api/auth?code={code}&state={state}
  42. code为获取token所需中间码
  43. state为授权链接的state用于防止越权,用途不明
  44. */
  45. // 访问以获取微信token
  46. log(Debug, format!("authing code+:`{}` state:`{}`",q.code,q.state));
  47. // reqwest::Client::builder().build()?.get(url).send().await;
  48. let webcli = match reqwest::Client::builder()
  49. .timeout(std::time::Duration::from_secs(3))
  50. .build()
  51. {
  52. Ok(cli) => cli,
  53. Err(e) => {
  54. log(Warning, format!("rewest client builder failed:: {e}"));
  55. return Redirect::to(format!("{}/null",crate::WEBP).as_str())
  56. }
  57. };
  58. log(Debug, format!("web client init"));
  59. // webcli.get("url").send();
  60. let a = match webcli.get(format!(
  61. "https://api.weixin.qq.com/sns/oauth2/access_token?appid={}&secret={}&code={}&grant_type=authorization_code",
  62. // "https://iotplatform.worldflying.cn/api/wx/auth?appid={}&secret={}&code={}&state={}&grant_type=authorization_code",
  63. APPID,
  64. APPSECRET,
  65. q.code,
  66. // q.state
  67. )).send().await {
  68. Ok(a) => {
  69. // log(Info, format!("dealing"));
  70. let v = a.text().await;
  71. log(Debug, format!("dealing\n{:?}",v));
  72. let v = if let Ok(v)=v {v}else {
  73. return Redirect::to(format!("{}/null",crate::WEBP).as_str());
  74. };
  75. match
  76. serde_json::from_str::<WxGetToken>(v.as_str())
  77. // a.json::<WxGetToken>().await
  78. {
  79. Ok(b) => b,
  80. Err(e) =>{
  81. log(Error, format!("redirect 2 {e}, raw:{v}"));
  82. return Redirect::to(format!("{}/null",crate::WEBP).as_str())
  83. }
  84. }
  85. },
  86. Err(e) => {
  87. log(Debug, format!("redirect 0 {e}"));
  88. return Redirect::to(format!("{}/null",crate::WEBP).as_str())
  89. }
  90. };
  91. // let host = headers.get("host")
  92. // .and_then(|hv| hv.to_str().ok())
  93. // .unwrap_or("localhost:3000");
  94. log(Debuging, format!("in authing"));
  95. let token=super::token(32);
  96. let res = super::check_openid(&state, a.openid.clone()).await;
  97. if let Ok((id,mqid)) = res{
  98. // 用户已经注册 函数末尾发生跳转到主页
  99. if let Err(e) = state.db_lite.execute("update user set token=? where id=?", (token.clone(), id)).await{
  100. println!("{e}");
  101. };
  102. // 已注册时绑定设备
  103. if let Some(sn)= q.state.strip_prefix("did="){
  104. log(Debuging, format!("got did: {}",sn));
  105. if let Err(e) = state.db_lite.execute("update device set belongto=? where sn=? and belongto=0", (id,sn)).await{
  106. println!("{e}");
  107. }else if let Ok(did) = state.db_lite.query("select id from device where sn=?", [sn], |r|{r.get::<usize,i64>(0)}).await{
  108. // if let Some(did)=state.db_lite.last_insert_rowid().await.ok(){ // 错误位置:update不会给last_insert_rowid
  109. if let Err(e) = state.db_lite.execute("insert into map_user_device (uid, did)values(?,?)", (id,did)).await{
  110. println!("{e}");
  111. } else{
  112. if let Some(mq) = state.mq_detail{
  113. if let Err(e)=mq.db_mq_map.execute(
  114. "insert into pub (clientid,topic,deadline)values(?,?,9223372036854775807),(?,?,9223372036854775807)",
  115. (mqid.clone(),format!("{}/cmd",sn),mqid.clone(),format!("/wf/Iot/device/{sn}"))).await{
  116. log(Warning, format!("on register with device: {e}"));
  117. };
  118. if let Err(e)=mq.db_mq_map.execute(
  119. "insert into sub (clientid,topic,deadline)values(?,?,9223372036854775807),(?,?,9223372036854775807)",
  120. (mqid.clone(),format!("{}/state",sn),mqid.clone(),format!("/wf/Iot/client/{sn}"))).await{
  121. log(Warning, format!("on register with device: {e}"));
  122. };
  123. }
  124. }
  125. };
  126. }
  127. } else if a.scope !="snsapi_userinfo"{
  128. // 用户未注册,跳转获取用户详细信息
  129. log(Debug, "send redirect for get uinfo".to_string());
  130. return Redirect::to(
  131. format!("https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx664469117500d259&redirect_uri=https%3A%2F%2Fwww.worldflying.cn%2Ftools%2Fwxredirect%2Fplc.html&response_type=code&scope=snsapi_userinfo&state={}#wechat_redirect",q.state).as_str()
  132. // format!("https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx664469117500d259&redirect_uri=https%3A%2F%2Fwww.worldflying.cn%2Ftools%2Fwxredirect%2Fiot.html&response_type=code&scope=snsapi_userinfo&state={}#wechat_redirect",q.state).as_str()
  133. )
  134. } else {
  135. // 带用户信息的重定向收取目标分支,保存用户数据并创建mqtt相关信息
  136. let b:WxUserInfo = if let Ok(b) = {if let Ok(b) = reqwest::get(format!(
  137. "https://api.weixin.qq.com/sns/userinfo?access_token={}&openid={}&lang=zh_CN",
  138. a.access_token,
  139. a.openid.clone()
  140. )).await{b.json().await} else {
  141. log(Info, "redirect 4".to_string());
  142. return Redirect::to(format!("{}/null",crate::WEBP).as_str())}}{b} else {
  143. log(Info, "redirect 5".to_string());
  144. return Redirect::to(format!("{}/null",crate::WEBP).as_str())};
  145. let mqid = format!("webu{}",super::token(5));
  146. if let Err(e) = state.db_lite.execute(
  147. "insert into user (uname,nickname,passwd,headimgurl,openid,sex,token,mqid) values(?,?,?,?,?,?,?,?)",
  148. (b.nickname.clone(),b.nickname.clone(),"",b.headimgurl,b.openid,b.sex,token.clone(),mqid.clone())).await{
  149. println!("{e}");
  150. }
  151. let uid = match state.db_lite.last_insert_rowid().await{
  152. Ok(id) => id,
  153. Err(e) => {
  154. println!("{e}");
  155. 0
  156. }
  157. };
  158. if let Err(e) = state.db_lite.execute(
  159. "insert into area (name,sup,createby)values(?,0,?)",
  160. (format!("{}的家",b.nickname.clone()),uid)
  161. ).await{println!("{e}")};
  162. let area_sup: i64;
  163. if let Err(e) = state.db_lite.execute(
  164. "insert into map_user_area (uid,aid)values(?,?)",
  165. [uid,{area_sup=match state.db_lite.last_insert_rowid().await{Ok(id)=>id,Err(e)=>{println!("{e}");0}};area_sup}]
  166. ).await{println!("{e}")};
  167. if let Err(e) = state.db_lite.execute(
  168. "insert into area (name,sup,createby)values('客厅',?,?)",
  169. [area_sup,uid]
  170. ).await{println!("{e}")};
  171. // 未注册时绑定设备
  172. if let Some(sn)= q.state.strip_prefix("did="){
  173. log(Debuging, format!("got did: {}",sn));
  174. if let Err(e) = state.db_lite.execute("update device set belongto=? where sn=? and belongto=0", (uid,sn)).await{
  175. println!("{e}");
  176. }else if let Ok(did) = state.db_lite.query("select id from device where sn=?", [sn], |r|{r.get::<usize,i64>(0)}).await{
  177. // if let Some(did)=state.db_lite.last_insert_rowid().await.ok(){ // 错误位置:update不会给last_insert_rowid
  178. if let Err(e) = state.db_lite.execute("insert into map_user_device (uid, did)values(?,?)", (uid,did)).await{
  179. println!("{e}");
  180. }
  181. };
  182. if let Some(mq) = state.mq_detail{
  183. if let Err(e)=mq.db_mq_map.execute(
  184. "insert into pub (clientid,topic,deadline)values(?,?,9223372036854775807),(?,?,9223372036854775807)",
  185. (mqid.clone(),format!("{}/cmd",sn),mqid.clone(),format!("/wf/Iot/device/{sn}"))).await{
  186. log(Warning, format!("on register with device: {e}"));
  187. };
  188. if let Err(e)=mq.db_mq_map.execute(
  189. "insert into sub (clientid,topic,deadline)values(?,?,9223372036854775807),(?,?,9223372036854775807)",
  190. (mqid.clone(),format!("{}/state",sn),mqid.clone(),format!("/wf/Iot/client/{sn}"))).await{
  191. log(Warning, format!("on register with device: {e}"));
  192. };
  193. }
  194. }
  195. log(Debug, "register success".to_string());
  196. // 注册成功 函数末尾发生跳转到主页
  197. // return Redirect::to(format!("http://124.222.106.170/plc_ctrl?token={}#{}",token.clone(),q.state).as_str());
  198. };
  199. // request::Request::get("body");
  200. // log(Info, format!("bad happend {:?}",res));
  201. log(Debug, format!("redirect back with token, state: {}",q.state));
  202. return Redirect::to(format!("{}?token={}{}",crate::WEBP,token.clone(),if q.state.starts_with("?"){format!("#{}",q.state)}else{"".to_string()}).as_str());
  203. // return Redirect::to(format!("{}?token={}",crate::WEBP,token.clone()).as_str());
  204. }