C#微信網頁授權登入(NET MVC)

風靈使發表於2018-09-12

##Token驗證
WeixinController.cs

using System.Web.Mvc;

namespace WeChat.Controllers
{
    public class WeixinController : Controller
    {
        public string Index()
        {
            var token = "chinalex"; //與微信公眾賬號後臺的Token設定保持一致,區分大小寫
            if (string.IsNullOrEmpty(token))
            {
                return string.Empty;
            }
            var echoString = Request.QueryString["echoStr"]; 
            //string signature = this.Request.QueryString["signature"];
            //string timestamp = this.Request.QueryString["timestamp"];
            //string nonce = this.Request.QueryString["nonce"];

            return echoString;
        }
    }
}

##HomeController.cs

using System.Diagnostics;
using System.IO;
using System.Net;
using System.Web.Mvc;
using Newtonsoft.Json;
using Wechat.Helper;
using WeChat.Helper;

namespace WeChat.Controllers
{
    public class HomeController : Controller
    {
        public static int sum;

        public static string openid; //使用者的唯一標識
        public static string nickname; //使用者暱稱
        public static string sex; //使用者的性別,值為1時是男性,值為2時是女性,值為0時是未知
        public static string province; //使用者個人資料填寫的省份
        public static string city; //普通使用者個人資料填寫的城市
        public static string country; //國家,如中國為CN
        public static string headimgurl; //使用者頭像
        public static string privilege; //使用者特權資訊,json 陣列,如微信沃卡使用者為(chinaunicom)
        public static string unionid; //只有在使用者將公眾號繫結到微信開放平臺帳號後,才會出現該欄位。

        private static userInfo usInfo;


        //
        // GET: /Home/
        //第一步:使用者同意授權,獲取code
        public ActionResult Index()
        {
            var flag = 0;
            var code = Request.QueryString["code"];
            var state = Request.QueryString["state"];
            if (code != "" && state != null && flag == 0)
            {
                flag = 1;
                at(code); //拿code獲取token跟openId
                ViewBag.Message_ViewBag = usInfo.nickname;
            }
            return View();
        }

        //第二步:通過code換取網頁授權access_token
        public void at(string code)
        {
            var AppID = "wxxxxxxx";
            var AppSecret = "fffffffffffffffffffff";
            var strUrl =
                "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code";
                
            strUrl = string.Format(strUrl, AppID, AppSecret, code);
            var request = (HttpWebRequest)WebRequest.Create(strUrl);
            var response = (HttpWebResponse)request.GetResponse();
            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            var at = JsonConvert.DeserializeObject<atoken>(responseString);
            rt(AppID, at.refresh_token);
        }


        //第三步:重新整理refresh_token(如果需要)
        public void rt(string AppID, string refresh_token)
        {
            var strUrl ="https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={0}&grant_type=refresh_token&refresh_token={1}";
            strUrl = string.Format(strUrl, AppID, refresh_token);
            var request = (HttpWebRequest)WebRequest.Create(strUrl);
            var response = (HttpWebResponse)request.GetResponse();
            var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
            var rt = JsonConvert.DeserializeObject<rtoken>(responseString);
            gUserInfo(rt.access_token, rt.openid);
        }

        //第四步:拉取使用者資訊(需scope為 snsapi_userinfo)
        [HttpGet]
        public void gUserInfo(string access_token, string openId)
        {
            sum = sum + 1;

            if (access_token != null)
            {
                var strUrl = "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN";
                strUrl = string.Format(strUrl, access_token, openId);

                var jsonStr = HttpCrossDomain.Get(strUrl);
                usInfo = new userInfo();
                usInfo.openid = Tools.GetJsonValue(jsonStr, "openid");
                usInfo.nickname = Tools.GetJsonValue(jsonStr, "nickname");
                usInfo.sex = Tools.GetJsonValue(jsonStr, "sex");
                usInfo.province = Tools.GetJsonValue(jsonStr, "province");
                usInfo.city = Tools.GetJsonValue(jsonStr, "city");
                usInfo.country = Tools.GetJsonValue(jsonStr, "country");
                usInfo.headimgurl = Tools.GetJsonValue(jsonStr, "headimgurl");
                usInfo.privilege = Tools.GetJsonValue(jsonStr, "privilege");
                usInfo.unionid = Tools.GetJsonValue(jsonStr, "unionid");
            }
            else
            {
                Debug.Write("沒有拿到access_token:" + sum);
                //return View();
            }
        }

        private class atoken
        {
            public string access_token { set; get; }
            public string expires_in { set; get; }
            public string refresh_token { set; get; }
            public string openid { set; get; }
            public string scope { set; get; }
        }

        private class rtoken
        {
            public string access_token { set; get; }
            public string expires_in { set; get; }
            public string refresh_token { set; get; }
            public string openid { set; get; }
            public string scope { set; get; }
        }

        private class userInfo
        {
            public string openid { set; get; }
            public string nickname { set; get; }
            public string sex { set; get; }
            public string province { set; get; }
            public string city { set; get; }
            public string country { set; get; }
            public string headimgurl { set; get; }
            public string privilege { set; get; }
            public string unionid { set; get; }
        }
    }
}

##HttpCrossDomain.cs

using System;
using System.IO;
using System.Net;
using System.Text;

namespace Wechat.Helper
{
    public class HttpCrossDomain
    {
        /// <summary>
        ///     跨域訪問
        /// </summary>
        /// <param name="url"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public static string Post(string url, string param, int time = 60000)
        {
            var address = new Uri(url);
            var request = WebRequest.Create(address) as HttpWebRequest;
            request.Method = "POST";
            request.ContentType = "application/json;charset=utf-8"; //"application/x-www-form-urlencoded";
            request.Timeout = time;
            var byteData = Encoding.UTF8.GetBytes(param == null ? "" : param);
            request.ContentLength = byteData.Length;
            using (var postStream = request.GetRequestStream())
            {
                postStream.Write(byteData, 0, byteData.Length);
            }
            var result = "";
            using (var response = request.GetResponse() as HttpWebResponse)
            {
                var reader = new StreamReader(response.GetResponseStream());
                result = reader.ReadToEnd();
            }
            return result;
        }

        /// <summary>
        ///     跨域訪問
        /// </summary>
        /// <param name="url"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public static string Get(string url, int time = 60000)
        {
            var address = new Uri(url);
            var request = WebRequest.Create(address) as HttpWebRequest;
            request.Method = "GET";
            request.ContentType = "application/json;charset=utf-8"; //"application/x-www-form-urlencoded";
            request.Timeout = time;
            var result = "";
            try
            {
                using (var response = request.GetResponse() as HttpWebResponse)
                {
                    var reader = new StreamReader(response.GetResponseStream());
                    result = reader.ReadToEnd();
                }
            }
            catch
            {
                result = "";
            }
            return result;
        }
    }
}

##Tools.cs

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Encoder = System.Drawing.Imaging.Encoder;

namespace WeChat.Helper
{
    public class Tools
    {
        private static readonly string[] strs =
        {
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
            "w", "x", "y", "z",
            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
            "W", "X", "Y", "Z"
        };

        /// <summary>
        ///     Sha1
        /// </summary>
        /// <param name="orgStr"></param>
        /// <param name="encode"></param>
        /// <returns></returns>
        public static string Sha1(string orgStr, string encode = "UTF-8")
        {
            var sha1 = new SHA1Managed();
            var sha1bytes = Encoding.GetEncoding(encode).GetBytes(orgStr);
            var resultHash = sha1.ComputeHash(sha1bytes);
            var sha1String = BitConverter.ToString(resultHash).ToLower();
            sha1String = sha1String.Replace("-", "");
            return sha1String;
        }

        #region 獲取Json字串某節點的值

        /// <summary>
        ///     獲取Json字串某節點的值
        /// </summary>
        public static string GetJsonValue(string jsonStr, string key)
        {
            var result = string.Empty;
            if (!string.IsNullOrEmpty(jsonStr))
            {
                key = "\"" + key.Trim('"') + "\"";
                var index = jsonStr.IndexOf(key) + key.Length + 1;
                if (index > key.Length + 1)
                {
                    //先截<span id="3_nwp" style="width: auto; height: auto; float: none;"><a id="3_nwl" href="http://cpro.baidu.com/cpro/ui/uijs.php?c=news&cf=5&ch=0&di=128&fv=17&jk=17f5c9861aa0f402&k=%B6%BA%BA%C5&k0=%B6%BA%BA%C5&kdi0=0&luki=2&n=10&p=baidu&q=00007110_cpr&rb=0&rs=1&seller_id=1&sid=2f4a01a86c9f517&ssp2=1&stid=0&t=tpclicked3_hc&tu=u1704338&u=http%3A%2F%2Fwww%2Edaxueit%2Ecom%2Farticle%2F5631%2Ehtml&urlid=0" target="_blank" mpid="3" style="text-decoration: none;"><span style="color:#0000ff;font-size:14px;width:auto;height:auto;float:none;">逗號</span></a></span>,若是最後一個,截“}”號,取最小值
                    var end = jsonStr.IndexOf(',', index);
                    if (end == -1)
                    {
                        end = jsonStr.IndexOf('}', index);
                    }

                    result = jsonStr.Substring(index, end - index);
                    result = result.Trim('"', ' ', '\''); //過濾引號或空格
                }
            }
            return result;
        }

        #endregion

        /// <summary>
        ///     建立時間戳
        /// </summary>
        /// <returns></returns>
        public static long CreatenTimestamp()
        {
            return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000)/10000000;
        }

        /// <summary>
        ///     建立隨機字串
        ///     本程式碼來自開源微信SDK專案:
        /// </summary>
        /// <returns></returns>
        public static string CreatenNonce_str()
        {
            var r = new Random();
            var sb = new StringBuilder();
            var length = strs.Length;
            for (var i = 0; i < 15; i++)
            {
                sb.Append(strs[r.Next(length - 1)]);
            }
            return sb.ToString();
        }

        /// <summary>
        ///     無失真壓縮圖片
        /// </summary>
        /// <param name="sFile">原圖片</param>
        /// <param name="dFile">壓縮後儲存位置</param>
        /// <param name="dHeight">高度</param>
        /// <param name="dWidth"></param>
        /// <param name="flag">壓縮質量 1-100</param>
        /// <returns></returns>
        public static bool GetPicThumbnail(string sFile, string dFile, int dHeight, int dWidth, int flag)
        {
            var iSource = Image.FromFile(sFile);

            var tFormat = iSource.RawFormat;

            int sW = 0, sH = 0;

            //按比例縮放

            var tem_size = new Size(iSource.Width, iSource.Height);


            if (tem_size.Width > dHeight || tem_size.Width > dWidth) //將**改成c#中的或者操作符號
            {
                if (tem_size.Width*dHeight > tem_size.Height*dWidth)
                {
                    sW = dWidth;

                    sH = dWidth*tem_size.Height/tem_size.Width;
                }

                else
                {
                    sH = dHeight;

                    sW = tem_size.Width*dHeight/tem_size.Height;
                }
            }

            else
            {
                sW = tem_size.Width;

                sH = tem_size.Height;
            }

            var ob = new Bitmap(dWidth, dHeight);

            var g = Graphics.FromImage(ob);

            g.Clear(Color.WhiteSmoke);

            g.CompositingQuality = CompositingQuality.HighQuality;

            g.SmoothingMode = SmoothingMode.HighQuality;

            g.InterpolationMode = InterpolationMode.HighQualityBicubic;

            g.DrawImage(iSource, new Rectangle((dWidth - sW)/2, (dHeight - sH)/2, sW, sH), 0, 0, iSource.Width,
                iSource.Height, GraphicsUnit.Pixel);

            g.Dispose();

            //以下程式碼為儲存圖片時,設定壓縮質量

            var ep = new EncoderParameters();

            var qy = new long[1];

            qy[0] = flag; //設定壓縮的比例1-100

            var eParam = new EncoderParameter(Encoder.Quality, qy);

            ep.Param[0] = eParam;

            try
            {
                var arrayICI = ImageCodecInfo.GetImageEncoders();

                ImageCodecInfo jpegICIinfo = null;

                for (var x = 0; x < arrayICI.Length; x++)
                {
                    if (arrayICI[x].FormatDescription.Equals("JPEG"))
                    {
                        jpegICIinfo = arrayICI[x];

                        break;
                    }
                }

                if (jpegICIinfo != null)
                {
                    ob.Save(dFile, jpegICIinfo, ep); //dFile是壓縮後的新路徑
                }

                else
                {
                    ob.Save(dFile, tFormat);
                }

                return true;
            }

            catch
            {
                return false;
            }

            finally
            {
                iSource.Dispose();

                ob.Dispose();
            }
        }

        /// <summary>
        ///     壓縮圖片
        /// </summary>
        /// <returns></returns>
        public static bool CompressImages(string pathOriginal, string pathDestination)
        {
            var files = Directory.GetFiles(pathOriginal);
            var bos = false;

            foreach (var file in files)
            {
                var strImgPathOriginal = pathOriginal + Path.GetFileName(file).Trim();
                if (File.Exists(strImgPathOriginal))
                {
                    //原始圖片存在

                    var strImgPath = pathDestination + Path.GetFileName(file).Trim();
                    if (!File.Exists(strImgPath))
                    {
                        //壓縮圖片不存在

                        //壓縮圖片
                        bos = GetPicThumbnail(strImgPathOriginal, strImgPath, 200, 200, 100);
                        if (!bos)
                        {
                            break;
                        }
                    }
                }
            }
            return true;
        }


        /// <summary>
        ///     無失真壓縮圖片
        /// </summary>
        /// <param name="sFile">原圖片Img</param>
        /// <param name="dFile">壓縮後儲存位置</param>
        /// <param name="dHeight">高度</param>
        /// <param name="dWidth"></param>
        /// <param name="flag">壓縮質量 1-100</param>
        /// <returns></returns>
        public static bool GetPicThumbnails(Image iSource, string dFile, int dHeight, int dWidth, int flag)
        {
            //System.Drawing.Image iSource = System.Drawing.Image.FromFile(sFile);

            var tFormat = iSource.RawFormat;

            int sW = 0, sH = 0;

            var temp = 0;
            //按比例縮放
            if (iSource.Width > iSource.Height)
            {
                temp = iSource.Height;
            }
            else
            {
                temp = iSource.Width;
            }


            var tem_size = new Size(temp, temp);


            if (tem_size.Width > dHeight || tem_size.Width > dWidth) //將**改成c#中的或者操作符號
            {
                if (tem_size.Width*dHeight > tem_size.Height*dWidth)
                {
                    sW = dWidth;

                    sH = dWidth*tem_size.Height/tem_size.Width;
                }

                else
                {
                    sH = dHeight;

                    sW = tem_size.Width*dHeight/tem_size.Height;
                }
            }

            else
            {
                sW = tem_size.Width;

                sH = tem_size.Height;
            }

            var ob = new Bitmap(dWidth, dHeight);

            var g = Graphics.FromImage(ob);

            g.Clear(Color.WhiteSmoke);

            g.CompositingQuality = CompositingQuality.HighQuality;

            g.SmoothingMode = SmoothingMode.HighQuality;

            g.InterpolationMode = InterpolationMode.HighQualityBicubic;

            g.DrawImage(iSource, new Rectangle((dWidth - sW)/2, (dHeight - sH)/2, sW, sH), 0, 0, iSource.Width,
                iSource.Height, GraphicsUnit.Pixel);

            g.Dispose();

            //以下程式碼為儲存圖片時,設定壓縮質量

            var ep = new EncoderParameters();

            var qy = new long[1];

            qy[0] = flag; //設定壓縮的比例1-100

            var eParam = new EncoderParameter(Encoder.Quality, qy);

            ep.Param[0] = eParam;

            try
            {
                var arrayICI = ImageCodecInfo.GetImageEncoders();

                ImageCodecInfo jpegICIinfo = null;

                for (var x = 0; x < arrayICI.Length; x++)
                {
                    if (arrayICI[x].FormatDescription.Equals("JPEG"))
                    {
                        jpegICIinfo = arrayICI[x];

                        break;
                    }
                }

                if (jpegICIinfo != null)
                {
                    ob.Save(dFile, jpegICIinfo, ep); //dFile是壓縮後的新路徑
                }

                else
                {
                    ob.Save(dFile, tFormat);
                }

                return true;
            }

            catch
            {
                return false;
            }

            finally
            {
                iSource.Dispose();

                ob.Dispose();
            }
        }


        /// <summary>
        ///     按照指定大小縮放圖片,但是為了保證圖片寬高比將對圖片從中心進行擷取,達到圖片不被拉伸的效果
        /// </summary>
        /// <param name="srcImage"></param>
        /// <param name="iWidth"></param>
        /// <param name="iHeight"></param>
        /// <returns></returns>
        public static Bitmap SizeImageWithOldPercent(Image srcImage, int iWidth, int iHeight)
        {
            try
            {
                // 要擷取圖片的寬度(臨時圖片) 
                var newW = srcImage.Width;
                // 要擷取圖片的高度(臨時圖片) 
                var newH = srcImage.Height;
                // 擷取開始橫座標(臨時圖片) 
                var newX = 0;
                // 擷取開始縱座標(臨時圖片) 
                var newY = 0;
                // 擷取比例(臨時圖片) 
                double whPercent = 1;
                whPercent = iWidth/(double) iHeight*(srcImage.Height/(double) srcImage.Width);
                if (whPercent > 1)
                {
                    // 當前圖片寬度對於要擷取比例過大時 
                    newW = int.Parse(Math.Round(srcImage.Width/whPercent).ToString());
                }
                else if (whPercent < 1)
                {
                    // 當前圖片高度對於要擷取比例過大時 
                    newH = int.Parse(Math.Round(srcImage.Height*whPercent).ToString());
                }
                if (newW != srcImage.Width)
                {
                    // 寬度有變化時,調整開始擷取的橫座標 
                    newX = Math.Abs(int.Parse(Math.Round(((double) srcImage.Width - newW)/2).ToString()));
                }
                else if (newH == srcImage.Height)
                {
                    // 高度有變化時,調整開始擷取的縱座標 
                    newY = Math.Abs(int.Parse(Math.Round((srcImage.Height - (double) newH)/2).ToString()));
                }
                // 取得符合比例的臨時檔案 
                var cutedImage = CutImage(srcImage, newX, newY, newW, newH);
                // 儲存到的檔案 
                var b = new Bitmap(iWidth, iHeight);
                var g = Graphics.FromImage(b);

                // 插值演算法的質量 
                g.InterpolationMode = InterpolationMode.Default;
                g.DrawImage(cutedImage, new Rectangle(0, 0, iWidth, iHeight),
                    new Rectangle(0, 0, cutedImage.Width, cutedImage.Height), GraphicsUnit.Pixel);
                g.Dispose();
                //return b;

                return cutedImage;
            }
            catch (Exception)
            {
                return null;
            }
        }


        /// <summary>
        ///     剪裁 -- 用GDI+
        /// </summary>
        /// <param name="b">原始Bitmap</param>
        /// <param name="StartX">開始座標X</param>
        /// <param name="StartY">開始座標Y</param>
        /// <param name="iWidth">寬度</param>
        /// <param name="iHeight">高度</param>
        /// <returns>剪裁後的Bitmap</returns>
        public static Bitmap CutImage(Image b, int StartX, int StartY, int iWidth, int iHeight)
        {
            if (b == null)
            {
                return null;
            }
            var w = b.Width;
            var h = b.Height;
            if (StartX >= w || StartY >= h)
            {
                // 開始擷取座標過大時,結束處理 
                return null;
            }
            if (StartX + iWidth > w)
            {
                // 寬度過大時只擷取到最大大小 
                iWidth = w - StartX;
            }
            if (StartY + iHeight > h)
            {
                // 高度過大時只擷取到最大大小 
                iHeight = h - StartY;
            }
            try
            {
                var bmpOut = new Bitmap(iWidth, iHeight);
                var g = Graphics.FromImage(bmpOut);
                g.DrawImage(b, new Rectangle(0, 0, iWidth, iHeight), new Rectangle(StartX, StartY, iWidth, iHeight),
                    GraphicsUnit.Pixel);
                g.Dispose();
                return bmpOut;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        ///     切原始圖片
        /// </summary>
        /// <param name="b"></param>
        /// <param name="StartX"></param>
        /// <param name="StartY"></param>
        /// <param name="iWidth"></param>
        /// <param name="iHeight"></param>
        /// <returns></returns>
        public static Bitmap CutImageOriginal(Image b)
        {
            var imageSource = b;
            var orgWidth = imageSource.Width;
            var orgHight = imageSource.Height;

            var width = 0;
            var height = 0;

            if (orgWidth > orgHight)
            {
                width = orgHight;
                height = orgHight;
            }
            else
            {
                width = orgWidth;
                height = orgWidth;
            }

            var cropArea = new Rectangle();

            var x = orgWidth/2 - width/2; //(145是從中間開始向兩邊截圖的寬度,可以自定義)
            var y = orgHight/2 - height/2;

            cropArea.X = x;
            cropArea.Y = y;
            cropArea.Width = width;
            cropArea.Height = height;

            var bmpImage = new Bitmap(imageSource);
            var bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);

            return bmpCrop;
        }

        /// <summary>
        ///     生成兩個數之間的隨機數
        /// </summary>
        /// <param name="min">最小值</param>
        /// <param name="max">最大值</param>
        /// <returns></returns>
        public static int GetRandNum(int min, int max)
        {
            var r = new Random(Guid.NewGuid().GetHashCode());
            return r.Next(min, max);
        }

        /// <summary>返回兩個經緯度座標點的距離(單位:米) by Alex.Y</summary>
        /// <param name="Longtiude">來源座標經度Y</param>
        /// <param name="Latitude">來源座標經度X</param>
        /// <param name="Longtiude2">目標座標經度Y</param>
        /// <param name="Latitude2">目標座標經度X</param>
        /// <returns>返回距離(米)</returns>
        public static double getMapDistance(double Longtiude, double Latitude, double Longtiude2, double Latitude2)
        {
            var lat1 = Latitude;
            var lon1 = Longtiude;
            var lat2 = Latitude2;
            var lon2 = Longtiude2;
            var earthRadius = 6371; //appxoximate radius in miles  6378.137

            var factor = Math.PI/180.0;
            var dLat = (lat2 - lat1)*factor;
            var dLon = (lon2 - lon1)*factor;
            var a = Math.Sin(dLat/2)*Math.Sin(dLat/2) + Math.Cos(lat1*factor)
                    *Math.Cos(lat2*factor)*Math.Sin(dLon/2)*Math.Sin(dLon/2);
            var c = 2*Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));

            var d = earthRadius*c*1000;

            return d;
        }
    }
}

@{
    ViewBag.Title = "Index";
}
<div style="border: 1px solid red; height: 600px; margin: 0 auto; width: 50%;">
    <div style="text-align: center;">
        <h2 style="margin-top: 20px;">
            微信授權登入
        </h2>

        <img src="~/Images/test1.png" alt="微信登入授權測試" style="height: 300px; width: 300px;" />

    </div>

    <br />

    暱稱:@Html.Encode(ViewBag.Message_ViewBag)


</div>

二維碼內容

https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxxxxxxxxxxx&redirect_uri=http://googles.ngrok.cc&response_type=
code&scope=snsapi_userinfo&state=STATE#wechat_redirect

相關文章