commit 0b047a9384e5132e73370b35f902ce59ccc73b71 Author: hupeh Date: Wed Aug 2 18:43:44 2023 +0800 oauth2示例代码 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4226214 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.idea +/*.iml +.DS_Store \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2d715fa --- /dev/null +++ b/go.mod @@ -0,0 +1,24 @@ +module nucleus + +go 1.20 + +require ( + github.com/go-oauth2/oauth2/v4 v4.5.2 + github.com/go-session/session v3.1.2+incompatible + gorm.io/gorm v1.25.2 +) + +require ( + github.com/golang-jwt/jwt v3.2.1+incompatible // indirect + github.com/google/uuid v1.1.1 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 // indirect + github.com/tidwall/buntdb v1.1.2 // indirect + github.com/tidwall/gjson v1.12.1 // indirect + github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect + github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e // indirect + github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bbff2dc --- /dev/null +++ b/go.sum @@ -0,0 +1,173 @@ +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= +github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= +github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= +github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/go-oauth2/oauth2/v4 v4.5.2 h1:CuZhD3lhGuI6aNLyUbRHXsgG2RwGRBOuCBfd4WQKqBQ= +github.com/go-oauth2/oauth2/v4 v4.5.2/go.mod h1:wk/2uLImWIa9VVQDgxz99H2GDbhmfi/9/Xr+GvkSUSQ= +github.com/go-session/session v3.1.2+incompatible h1:yStchEObKg4nk2F7JGE7KoFIrA/1Y078peagMWcrncg= +github.com/go-session/session v3.1.2+incompatible/go.mod h1:8B3iivBQjrz/JtC68Np2T1yBBLxTan3mn/3OM0CyRt0= +github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= +github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= +github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= +github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/tidwall/btree v0.0.0-20191029221954-400434d76274 h1:G6Z6HvJuPjG6XfNGi/feOATzeJrfgTNJY+rGrHbA04E= +github.com/tidwall/btree v0.0.0-20191029221954-400434d76274/go.mod h1:huei1BkDWJ3/sLXmO+bsCNELL+Bp2Kks9OLyQFkzvA8= +github.com/tidwall/buntdb v1.1.2 h1:noCrqQXL9EKMtcdwJcmuVKSEjqu1ua99RHHgbLTEHRo= +github.com/tidwall/buntdb v1.1.2/go.mod h1:xAzi36Hir4FarpSHyfuZ6JzPJdjRZ8QlLZSntE2mqlI= +github.com/tidwall/gjson v1.3.4/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls= +github.com/tidwall/gjson v1.12.1 h1:ikuZsLdhr8Ws0IdROXUS1Gi4v9Z4pGqpX/CvJkxvfpo= +github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb h1:5NSYaAdrnblKByzd7XByQEJVT8+9v0W/tIY0Oo4OwrE= +github.com/tidwall/grect v0.0.0-20161006141115-ba9a043346eb/go.mod h1:lKYYLFIr9OIgdgrtgkZ9zgRxRdvPYsExnYBsEAd8W5M= +github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e h1:+NL1GDIUOKxVfbp2KoJQD9cTQ6dyP2co9q4yzmT9FZo= +github.com/tidwall/rtree v0.0.0-20180113144539-6cd427091e0e/go.mod h1:/h+UnNGt0IhNNJLkGikcdcJqm66zGD/uJGMRxK/9+Ao= +github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563 h1:Otn9S136ELckZ3KKDyCkxapfufrqDqwmGjcHfAyXRrE= +github.com/tidwall/tinyqueue v0.0.0-20180302190814-1e39f5511563/go.mod h1:mLqSmt7Dv/CNneF2wfcChfN1rvapyQr01LGKnKex0DQ= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.34.0 h1:d3AAQJ2DRcxJYHm7OXNXtXt2as1vMDfxeIcFvhmGGm4= +github.com/valyala/fasthttp v1.34.0/go.mod h1:epZA5N+7pY6ZaEKRmstzOuYJx9HI8DI1oaCGZpdH4h0= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho= +gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= diff --git a/internal/controller.go b/internal/controller.go new file mode 100644 index 0000000..c2c9a50 --- /dev/null +++ b/internal/controller.go @@ -0,0 +1,21 @@ +package internal + +import ( + "log" + "net/http" + "os" +) + +type Controller struct{} + +func (c *Controller) Render(w http.ResponseWriter, r *http.Request, t string) { + file, err := os.Open(t) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), 500) + return + } + defer file.Close() + fi, _ := file.Stat() + http.ServeContent(w, r, file.Name(), fi.ModTime(), file) +} diff --git a/internal/controllers/oauth2_controller.go b/internal/controllers/oauth2_controller.go new file mode 100644 index 0000000..176faf3 --- /dev/null +++ b/internal/controllers/oauth2_controller.go @@ -0,0 +1,223 @@ +package controllers + +import ( + "context" + "encoding/json" + "errors" + "github.com/go-oauth2/oauth2/v4" + "github.com/go-oauth2/oauth2/v4/manage" + "github.com/go-oauth2/oauth2/v4/models" + "github.com/go-oauth2/oauth2/v4/server" + "github.com/go-oauth2/oauth2/v4/store" + "github.com/go-session/session" + "log" + "net/http" + "nucleus/internal" + "time" +) + +type UserInfo struct { + Username string `json:"username"` + Gender string `json:"gender"` +} + +var manager *manage.Manager +var srv *server.Server +var userInfoMap = make(map[string]UserInfo) + +type Oauth2Controller struct { + internal.Controller +} + +func (c *Oauth2Controller) Init() { + clientStore := store.NewClientStore() + clientStore.Set("juejin", &models.Client{ID: "juejin", Secret: "xxxxx", Domain: "http://juejin.com"}) + + // 设置 manager, manager 参与校验 code/access token 请求 + manager = manage.NewDefaultManager() + + // 校验 redirect_uri 和 client 的 Domain, 简单起见, 不做校验 + manager.SetValidateURIHandler(func(baseURI, redirectURI string) error { + return nil + }) + + manager.MustTokenStorage(store.NewMemoryTokenStore()) + + // manger 包含 client 信息 + manager.MapClientStorage(clientStore) + + // 也包含 manger, client 信息 + srv = server.NewServer(server.NewConfig(), manager) + + // 根据 client id 从 manager 中获取 client info, 在获取 access token 校验过程中会被用到 + srv.SetClientInfoHandler(func(r *http.Request) (clientID, clientSecret string, err error) { + clientInfo, err := srv.Manager.GetClient(r.Context(), r.URL.Query().Get("client_id")) + if err != nil { + log.Println(err) + return "", "", err + } + return clientInfo.GetID(), clientInfo.GetSecret(), nil + }) + + // 设置为 authorization code 模式 + srv.SetAllowedGrantType(oauth2.AuthorizationCode) + + // authorization code 模式, 第一步获取code,然后再用code换取 access token, 而不是直接获取 access token + srv.SetAllowedResponseType(oauth2.Code) + + // 校验授权请求用户的handler, 会重定向到 登陆页面, 返回"", nil + srv.SetUserAuthorizationHandler(handleUserAuthorization) + + // 校验授权请求的用户的账号密码, 给 LoginHandler 使用, 简单起见, 只允许一个用户授权 + srv.SetPasswordAuthorizationHandler(func(ctx context.Context, clientID, username, password string) (userID string, err error) { + if username == "Tom" && password == "123456" { + return "0001", nil + } + return "", errors.New("username or password error") + }) + + // 允许使用 get 方法请求授权 + srv.SetAllowGetAccessRequest(true) + + // 储存用户信息的一个 map + userInfoMap["0001"] = UserInfo{ + "Tom", "Male", + } +} + +// HandleAuthorizeRequest 授权入口 +func (c *Oauth2Controller) HandleAuthorizeRequest(w http.ResponseWriter, r *http.Request) { + err := srv.HandleAuthorizeRequest(w, r) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusBadRequest) + } +} + +// HandleLoginRequest 登陆入口 +func (c *Oauth2Controller) HandleLoginRequest(w http.ResponseWriter, r *http.Request) { + sessionStore, err := session.Start(r.Context(), w, r) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if r.Method == http.MethodPost { + userId, err := srv.PasswordAuthorizationHandler( + r.Context(), + r.FormValue("client_id"), + r.FormValue("username"), + r.FormValue("password"), + ) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusUnauthorized) + return + } + + // 保存登录状态 + sessionStore.Set("LoggedInUserId", userId) + sessionStore.Save() + + // 跳转到 同意授权页面 + w.Header().Set("Location", "/oauth2/agree-auth") + w.WriteHeader(http.StatusFound) + return + } + + // 若请求方法错误, 提供login.html页面 + c.Render(w, r, "static/login.html") +} + +// HandleAgreeAuthRequest 同意授权的页面 +func (c *Oauth2Controller) HandleAgreeAuthRequest(w http.ResponseWriter, r *http.Request) { + store, err := session.Start(r.Context(), w, r) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + // 如果没有查询到登陆状态, 则跳转到 登陆页面 + if _, ok := store.Get("LoggedInUserId"); !ok { + w.Header().Set("Location", "/oauth2/login") + w.WriteHeader(http.StatusFound) + return + } + + // 如果有登陆状态, 会跳转到 确认授权页面 + c.Render(w, r, "static/agree-auth.html") +} + +// HandleAccessTokenRequest 使用 code 换取 access token +func (c *Oauth2Controller) HandleAccessTokenRequest(w http.ResponseWriter, r *http.Request) { + err := srv.HandleTokenRequest(w, r) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusBadRequest) + } +} + +// HandleUserInfoRequest 使用 access_token 换取用户信息 +func (c *Oauth2Controller) HandleUserInfoRequest(w http.ResponseWriter, r *http.Request) { + // 获取 access token + accessToken, ok := srv.BearerAuth(r) + if !ok { + log.Println("Failed to get access token from request") + return + } + + rootCtx := context.Background() + ctx, cancelFunc := context.WithTimeout(rootCtx, time.Second) + defer cancelFunc() + + // 从 access token 中获取 信息 + tokenInfo, err := srv.Manager.LoadAccessToken(ctx, accessToken) + if err != nil { + log.Println(err) + return + } + + // 获取 user id + userId := tokenInfo.GetUserID() + grantScope := tokenInfo.GetScope() + + userInfo := UserInfo{} + + // 根据 grant scope 决定获取哪些用户信息 + if grantScope != "read_user_info" { + log.Println("invalid grant scope") + w.Write([]byte("invalid grant scope")) + return + } + + userInfo = userInfoMap[userId] + resp, err := json.Marshal(userInfo) + w.Write(resp) + return +} + +// AuthorizeHandler 内部使用, 用于查看是否有登陆状态 +func handleUserAuthorization(w http.ResponseWriter, r *http.Request) (userId string, err error) { + store, err := session.Start(r.Context(), w, r) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + uid, ok := store.Get("LoggedInUserId") + // 如果没有查询到登陆状态, 则跳转到登陆页面 + if !ok { + if r.Form == nil { + r.ParseForm() + } + + w.Header().Set("Location", "/oauth2/login") + w.WriteHeader(http.StatusFound) + return "", nil + } + // 若有登录状态, 返回 user id + userId = uid.(string) + return userId, nil +} diff --git a/internal/entities/client_entity.go b/internal/entities/client_entity.go new file mode 100644 index 0000000..9b16e7a --- /dev/null +++ b/internal/entities/client_entity.go @@ -0,0 +1,17 @@ +package entities + +import ( + "gorm.io/gorm" + "time" +) + +type Client struct { + Id uint `json:"id"` + AccessKey string `json:"access_key" gorm:"primaryKey"` + SecretKey string `json:"secret_key"` + Domain string `json:"domain"` + Public bool `json:"public"` + CreatedAt time.Time `json:"create_time"` + UpdatedAt time.Time `json:"update_time"` + DeletedAt gorm.DeletedAt `json:"delete_time,omitempty" gorm:"index"` +} diff --git a/internal/entities/user_data_entity.go b/internal/entities/user_data_entity.go new file mode 100644 index 0000000..b2d6e16 --- /dev/null +++ b/internal/entities/user_data_entity.go @@ -0,0 +1,9 @@ +package entities + +type UserData struct { + Id uint `json:"id" gorm:"primaryKey"` + Uid uint `json:"uid"` + Nickname string `json:"nickname"` + Gender string `json:"gender"` + Avatar string `json:"avatar"` +} diff --git a/internal/entities/user_entity.go b/internal/entities/user_entity.go new file mode 100644 index 0000000..8e7930c --- /dev/null +++ b/internal/entities/user_entity.go @@ -0,0 +1,22 @@ +package entities + +import ( + "database/sql" + "gorm.io/gorm" + "time" +) + +type User struct { + Id uint `json:"id" gorm:"primaryKey"` + Nickname string `json:"secret_key"` + Gender string `json:"gender"` + Avatar string `json:"avatar"` + Username sql.NullString `json:"username" gorm:"unique"` + Email sql.NullString `json:"email" gorm:"unique"` + PhoneNumber sql.NullString `json:"phone_number" gorm:"unique"` + Password sql.NullString `json:"password"` + Data []*UserData `json:"data,omitempty" gorm:"foreignKey:Uid;references:Id"` + CreatedAt time.Time `json:"create_time"` + UpdatedAt time.Time `json:"update_time"` + DeletedAt gorm.DeletedAt `json:"delete_time,omitempty" gorm:"index"` +} diff --git a/internal/oauth2/client_store.go b/internal/oauth2/client_store.go new file mode 100644 index 0000000..929a8c2 --- /dev/null +++ b/internal/oauth2/client_store.go @@ -0,0 +1,36 @@ +package oauth2 + +import ( + "context" + "errors" + "github.com/go-oauth2/oauth2/v4" + "github.com/go-oauth2/oauth2/v4/models" + "gorm.io/gorm" + "nucleus/internal/entities" +) + +type ClientStore struct{} + +func (c *ClientStore) GetByID(ctx context.Context, id string) (oauth2.ClientInfo, error) { + db, ok := ctx.Value("db").(*gorm.DB) + if !ok { + return nil, errors.New("missing database object") + } + + var client entities.Client + err := db.First(&client, "id=?", id).Error + if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, errors.New("no client found") + } + return nil, err + } + + return &models.Client{ + ID: client.AccessKey, + Secret: client.SecretKey, + Domain: client.Domain, + Public: client.Public, + //UserID: "", + }, nil +} diff --git a/internal/oauth2/controller.go b/internal/oauth2/controller.go new file mode 100644 index 0000000..2d2147a --- /dev/null +++ b/internal/oauth2/controller.go @@ -0,0 +1 @@ +package oauth2 diff --git a/internal/oauth2/init.go b/internal/oauth2/init.go new file mode 100644 index 0000000..2a53052 --- /dev/null +++ b/internal/oauth2/init.go @@ -0,0 +1,30 @@ +package oauth2 + +import ( + "github.com/go-oauth2/oauth2/v4" + "github.com/go-oauth2/oauth2/v4/manage" + "github.com/go-oauth2/oauth2/v4/server" +) + +var ( + manager *manage.Manager + srv *server.Server +) + +func Init() { + manager = manage.NewDefaultManager() + manager.SetValidateURIHandler(nil) + //manager.MustTokenStorage() + manager.MapClientStorage(&ClientStore{}) + + srv = server.NewServer(server.NewConfig(), manager) + srv.SetClientInfoHandler(nil) + srv.SetAllowedGrantType(oauth2.AuthorizationCode) + // authorization code 模式, 第一步获取code,然后再用code换取 access token, 而不是直接获取 access token + srv.SetAllowedResponseType(oauth2.Code) + // 校验授权请求用户的handler, 会重定向到 登陆页面, 返回"", nil + srv.SetUserAuthorizationHandler(nil) + // 校验授权请求的用户的账号密码, 给 LoginHandler 使用, 简单起见, 只允许一个用户授权 + srv.SetPasswordAuthorizationHandler(nil) + srv.SetAllowGetAccessRequest(true) +} diff --git a/internal/oauth2/token_store.go b/internal/oauth2/token_store.go new file mode 100644 index 0000000..2d2147a --- /dev/null +++ b/internal/oauth2/token_store.go @@ -0,0 +1 @@ +package oauth2 diff --git a/main/main.go b/main/main.go new file mode 100644 index 0000000..397c61c --- /dev/null +++ b/main/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "net/http" + "nucleus/internal/controllers" +) + +func main() { + oauth2 := &controllers.Oauth2Controller{} + + oauth2.Init() + + // auth_server 授权入口 + http.HandleFunc("/oauth2/authorize", oauth2.HandleAuthorizeRequest) + + // auth_server 发现未登录状态, 跳转到的登录handler + http.HandleFunc("/oauth2/login", oauth2.HandleLoginRequest) + + // auth_server拿到 client以后重定向到的地址, 也就是 auth_client 获取到了code, 准备用code换取access_token + //http.HandleFunc("/oauth2/code_to_token", internal.CodeToToken) + + // auth_server 处理由code 换取access token 的handler + http.HandleFunc("/oauth2/token", oauth2.HandleAccessTokenRequest) + + // 登录完成, 同意授权的页面 + http.HandleFunc("/oauth2/agree-auth", oauth2.HandleAgreeAuthRequest) + + // access token 换取用户信息的handler + http.HandleFunc("/oauth2/userinfo", oauth2.HandleUserInfoRequest) + + http.Handle("/", http.FileServer(http.Dir("./static"))) + + errChan := make(chan error) + go func() { + errChan <- http.ListenAndServe(":9001", nil) + }() + err := <-errChan + if err != nil { + fmt.Println("Hello internal stop running.") + } + +} diff --git a/static/agree-auth.html b/static/agree-auth.html new file mode 100644 index 0000000..fb1f92c --- /dev/null +++ b/static/agree-auth.html @@ -0,0 +1,12 @@ + + + + + Title + + +
+ +
+ + diff --git a/static/code-to-user-info.html b/static/code-to-user-info.html new file mode 100644 index 0000000..53633c4 --- /dev/null +++ b/static/code-to-user-info.html @@ -0,0 +1,63 @@ + + + + + Title + + + + + + diff --git a/static/home.html b/static/home.html new file mode 100644 index 0000000..66401ae --- /dev/null +++ b/static/home.html @@ -0,0 +1,12 @@ + + + + + Title + + + +

我的网站

+ + + \ No newline at end of file diff --git a/static/login.html b/static/login.html new file mode 100644 index 0000000..b6f9cf1 --- /dev/null +++ b/static/login.html @@ -0,0 +1,43 @@ + + + + + Title + + + + +
+
+ 登陆 +
+ + +
+
+
+ + 忘记密码 +
+ +
+
+ +
+
+
+ 新用户登陆?创建账号 +
+
+ +