GO之认证与授权

 一般公司项目比较多,比较分散,但是对于都是公司的用户来说,用户数据一般是共享的,所以集成统一认证与授权的功能一般就必不可少,这样可以实现一个用户,分配一点权限,能访问公司很多项目.  

  一般的认证与授权方案有 OAuth、分布式 Session、OpenID 和 JWT 等.目前常用的是OAuth2,其重点在于为Web应用程序、桌面应用程序、移动设备以及室内设备的授权流程提供简单的客户端开发方式。它为第三方应用提供对HTTP服务的有限访问,既可以是资源拥有者通过授权允许第三方应用获取HTTP服务,也可以是第三方以自己的名义获取访问权限。

OAuth2 中主要分为了4种角色(重点核心)

1.resource owner 资源所有者,是能够对受保护的资源授予访问权限的实体,可以是一个用户,这时会被称为end-user。


2.resource server 资源服务器,持有受保护的资源,允许持有访问令牌(access token)的请求访问受保护资源。


3.client 客户端,持有资源所有者的授权,代表资源所有者对受保护资源进行访问。


4.authorization server 授权服务器,对资源所有者的授权进行认证,成功后向客户端发送访问令牌。

(所有的操作都是围绕这四种角色来开展的.)

官方有一个流程图:

主要是六步操作:

1.client请求Resource owner  来 获取授权;
2.Resource owner 同意授权,返回授权许可(Authorization Grant);
3.client携带Authorization Grant要求授权Resource Server 进行认证,并发送一个token令牌;
4.Resource Server 对client进行身份验证,并认证Authorization Grant,如果有效,返回token令牌;
5.client携带Authorization Grant向Resource Server请求受保护资源的访问;
6.Resource Server验证token令牌,如果有效,接受访问请求,返回受保护资源。

扫描二维码关注公众号,回复: 12424533 查看本文章

授权类型

  OAuth2默认定了四种授权类型

      1.authorization code 授权码类型

      2.implicit 简化类型(也称为隐式类型)

      3.resource owner password credentials 密码类型

      4. client credential 客户端类型

下面主要说一下客户端类型

具体代码如下:(着重看每个方法上面的注释,可以便于理解)

package main

import (
	"encoding/json"
	"fmt"
	"github.com/google/uuid"
	"gopkg.in/oauth2.v3/errors"
	"gopkg.in/oauth2.v3/manage"
	"gopkg.in/oauth2.v3/models"
	"gopkg.in/oauth2.v3/server"
	"gopkg.in/oauth2.v3/store"
	"log"
	"net/http"
)

func main(){
	clientStore, srv := InitOauthManager()
	/**
	    注册获取  clientId和clientSecret(     1.client请求Resource owner 来 获取授权;  )
	 */
	http.HandleFunc("/route", func(w http.ResponseWriter, r *http.Request) {
		clientId := uuid.New().String()[:8]
		clientSecret := uuid.New().String()[:8]
		err := clientStore.Set(clientId, &models.Client{
			ID:     clientId,
			Secret: clientSecret,
		})
		if err != nil {
			fmt.Println(err.Error())
		}
		w.Header().Set("Content-Type", "application/json")
		/**
		  //(2.Resource owner 同意授权,返回授权许可(Authorization Grant))
		 */
		json.NewEncoder(w).Encode(map[string]string{"CLIENT_ID": clientId, "CLIENT_SECRET": clientSecret}) //实际项目中一般存到数据库或者redis

	})


	/**
	    获取access_token( 3.client携带Authorization Grant要求授权Resource Server 进行认证,并发送一个token令牌;
	         			  4.Resource Server 对client进行身份验证,并认证Authorization Grant,如果有效,返回token令牌)
	 */
	http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
		srv.HandleTokenRequest(w, r)
	})


   /**
      带着access_token 访问路径(5.client携带Authorization Grant向Resource Server请求受保护资源的访问;)
    */
	http.HandleFunc("/test01", validateToken(func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("HelloWord"))
	}, srv))
	log.Fatal(http.ListenAndServe(":8888", nil))
}




/**
    token校验(6.Resource Server验证token令牌,如果有效,接受访问请求,返回受保护资源。)
 */
func validateToken(f http.HandlerFunc, srv *server.Server) http.HandlerFunc {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, err := srv.ValidationBearerToken(r)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		f.ServeHTTP(w, r)
	})
}



//初始化OauthManager
func InitOauthManager() (*store.ClientStore, *server.Server) {
	manager := manage.NewDefaultManager()
	manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)
	manager.MustTokenStorage(store.NewMemoryTokenStore())
	clientStore := store.NewClientStore()
	manager.MapClientStorage(clientStore)
	srv := server.NewDefaultServer(manager)
	srv.SetAllowGetAccessRequest(true)
	srv.SetClientInfoHandler(server.ClientFormHandler)
	manager.SetRefreshTokenCfg(manage.DefaultRefreshTokenCfg)
	srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
		log.Println("Internal Error:", err.Error())
		return
	})
	srv.SetResponseErrorHandler(func(re *errors.Response) {
		log.Println("Response Error:", re.Error.Error())
	})
	return clientStore, srv
}

1.首先我们启动项目.访问: http://localhost:8888/route  获取  clientId  和  clientSecret 

2.然后访问:  http://localhost:8888/token?grant_type=client_credentials&client_id=012eaf30&client_secret=298262d9  获取 到 access_token

3.在访问 :http://localhost:8888/test01?access_token=P8AR0LRKOLOYEMV9ACUXWG  可以看到返回的值

4.我们不加access_token或者修改下这个access_token  看是否还能获取到响应内容呢?

  1.修改access_token 发现:

2.不加access_token 

可以看到 没有正确的token令牌 是不让我们访问的,至此,我们整个模拟流程走通了.

Oauth支持的5类 grant_type 及说明


authorization_code — 授权码模式(即先登录获取code,再获取token)

password — 密码模式(将用户名,密码传过去,直接获取token)

client_credentials — 客户端模式(无用户,用户向客户端注册,然后客户端以自己的名义向’服务端’获取资源)

implicit — 简化模式(在redirect_uri 的Hash传递token; Auth客户端运行在浏览器中,如JS,Flash)

refresh_token — 刷新access_token

未完待续....

猜你喜欢

转载自blog.csdn.net/FindHuni/article/details/105840051