// Rota para autenticacao customizada
r.POST("/custom-signin", ctrl.handleCustomSignIn)
Eu recebo no input
- JWT Token da rede social(
input.Token
) - Qual rede social (
input.Provider
) - FederationID (
input.GoogleID
||input.FacebookID
)
// INICIO Controller Autenticacao
func (c *authController) handleCustomSignIn(ctx echo.Context) error {
context := context.New()
txn := ctx.Get(domain.NRTransactionKey)
context.Set(domain.NRTransactionKey, txn)
input := auth.UserDataCognito{}
err := ctx.Bind(&input)
if err != nil {
return errors.NewValidationError("", "Formato de entrada inválido")
}
cognitoService := auth.NewCognitoService()
// Validate token
err = auth.ValidateFederationToken(&input)
if err != nil {
return routeutils.HandleAPIError(ctx, errors.Wrap(err))
}
// Map federationIDs
federationID := map[string]string{
"google": input.GoogleID,
"facebook": input.FacebookID,
}
// Get user on Cognito with userID
user, err := c.svc.User.GetByFederationIDorEmail(context, federationID[input.Provider], input.Email)
if err != nil {
return routeutils.HandleAPIError(ctx, errors.Wrap(err))
}
// If user not found - Create a New
if user.ID == 0 {
userDataCognito, err := cognitoService.SignUp(input)
if err != nil {
return errors.NewHTTPError(403, err.Error())
}
input.ID = userDataCognito.ID
user := mapping.AuthCognitoToUserEntity(input)
user, err = c.svc.User.Insert(context, user)
if err != nil {
return routeutils.HandleAPIError(ctx, errors.Wrap(err))
}
}
// If user found - generate token
result, err := cognitoService.CustomSignIn(input)
if err != nil {
return errors.NewHTTPError(403, err.Error())
}
user, err = c.svc.User.GetByEmail(context, input.Email)
if err != nil {
return routeutils.HandleAPIError(ctx, errors.Wrap(err))
}
response := map[string]interface{}{
"token": result.IdToken,
"refresh_token": result.RefreshToken,
"expire_in": result.ExpiresIn,
"user": mapping.UserEntityToResponse(user),
}
return routeutils.ResponseAPIOK(ctx, response)
}
// FIM Controller
Dentro do metodo cognitoService.CustomSignIn(input)
Eu crio um novo JWT
// Auth
func ValidateFederationToken(input *UserDataCognito) error {
switch input.Provider {
case "google":
return validateGoogleToken(input)
case "facebook":
return validateFacebookToken(input)
}
return nil
}
func validateFacebookToken(input *UserDataCognito) error {
url := "https://graph.facebook.com/v3.2/me?fields=id,name,email"
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return errors.Wrap(err)
}
req.Header.Add("Host", "graph.facebook.com")
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", input.Token))
res, err := http.DefaultClient.Do(req)
if err != nil {
return errors.Wrap(err)
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return errors.Wrap(err)
}
if res.StatusCode != http.StatusOK {
return errors.NewForbiddenError("Invalid Token")
}
var response FacebookData
err = json.Unmarshal(body, &response)
if err != nil {
return errors.Wrap(err)
}
input.Name = response.Name
input.Email = response.Email
input.FacebookID = response.ID
input.Password = strconv.FormatInt(time.Now().UnixNano(), 10)[0:9] // Random Password
return nil
}
func validateGoogleToken(input *UserDataCognito) error {
url := fmt.Sprintf("https://oauth2.googleapis.com/tokeninfo?id_token=%s", input.Token)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return errors.Wrap(err)
}
req.Header.Add("Host", "oauth2.googleapis.com")
req.Header.Add("accept-encoding", "gzip, deflate")
res, err := http.DefaultClient.Do(req)
if err != nil {
return errors.Wrap(err)
}
var reader io.ReadCloser
switch res.Header.Get("Content-Encoding") {
case "gzip":
reader, err = gzip.NewReader(res.Body)
defer reader.Close()
default:
reader = res.Body
}
defer res.Body.Close()
body, err := ioutil.ReadAll(reader)
var response GoogleData
err = json.Unmarshal(body, &response)
if err != nil {
return errors.Wrap(err)
}
input.Name = response.Name
input.Email = response.Email
input.GoogleID = response.Sub
input.Password = strconv.FormatInt(time.Now().UnixNano(), 10)[0:9] // Random Password
return nil
}