mirror of
https://github.com/semaphoreui/semaphore.git
synced 2025-01-20 15:29:28 +01:00
Login working
This commit is contained in:
parent
0f180756ab
commit
ad860ef236
@ -1,28 +1,25 @@
|
||||
create table user (
|
||||
`id` varchar (255) not null comment "UUID v4",
|
||||
`created` datetime not null default NOW() comment "Created timestamp",
|
||||
`id` int(11) not null auto_increment primary key,
|
||||
`created` datetime not null default NOW(),
|
||||
`username` varchar(255) not null comment "Username, unique",
|
||||
`name` varchar(255) not null comment "Full name",
|
||||
`email` varchar(255) not null comment "Email, unique",
|
||||
`password` varchar(255) not null comment "Password",
|
||||
|
||||
UNIQUE KEY `username` (`username`),
|
||||
UNIQUE KEY `email` (`email`),
|
||||
PRIMARY KEY `id` (`id`)
|
||||
UNIQUE KEY `email` (`email`)
|
||||
) ENGINE=InnoDB CHARSET=utf8;
|
||||
|
||||
create table project (
|
||||
`id` varchar (255) not null comment "UUID v4",
|
||||
`id` int(11) not null auto_increment primary key,
|
||||
`created` datetime not null default NOW() comment "Created timestamp",
|
||||
`name` varchar(255) not null comment "Project name",
|
||||
|
||||
PRIMARY KEY `id` (`id`)
|
||||
`name` varchar(255) not null comment "Project name"
|
||||
) ENGINE=InnoDB CHARSET=utf8;
|
||||
|
||||
create table project__user (
|
||||
`project_id` varchar (255) not null comment "Project ID",
|
||||
`project_id` int(11) not null,
|
||||
`user_id` varchar (255) not null comment "User ID",
|
||||
`admin` tinyint (1) not null default 0 comment `Gives user god-like privileges`,
|
||||
`admin` tinyint (1) not null default 0 comment 'Gives user god-like privileges',
|
||||
|
||||
UNIQUE KEY `id` (`project_id`, `user_id`)
|
||||
) ENGINE=InnoDB CHARSET=utf8;
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID string `db:"id" json:"id"`
|
||||
ID int `db:"id" json:"id"`
|
||||
Created time.Time `db:"created" json:"created"`
|
||||
Username string `db:"username" json:"username"`
|
||||
Name string `db:"name" json:"name"`
|
||||
|
@ -6,9 +6,9 @@
|
||||
span(ng-bind="status")
|
||||
|
||||
.form-group(style="margin-top: 25px"): .col-sm-12
|
||||
input.text-center.form-control.input-lg(type="email" ng-model="user.auth" placeholder="Email / Username")
|
||||
input.text-center.form-control.input-lg(type="text" ng-model="user.auth" placeholder="Email / Username")
|
||||
.form-group: .col-sm-12
|
||||
input.text-center.form-control.input-lg(type="password" required ng-model="user.password" placeholder="Password")
|
||||
input.text-center.form-control.input-lg(type="password" ng-model="user.password" placeholder="Password")
|
||||
|
||||
.form-group(style="margin-top: 25px"): .col-sm-12
|
||||
button.btn.btn-primary.btn-block.btn-lg(ng-click="authenticate(user)") Sign In
|
@ -2,6 +2,22 @@ var app = angular.module('semaphore', ['scs.couch-potato', 'ui.router', 'ui.boot
|
||||
|
||||
couchPotato.configureApp(app);
|
||||
|
||||
app.config(['$httpProvider', function ($httpProvider) {
|
||||
$httpProvider.interceptors.push(['$q', '$injector', '$log', function ($q, $injector, $log) {
|
||||
return {
|
||||
request: function (request) {
|
||||
var url = request.url;
|
||||
if (!(url.indexOf('/public') !== -1 || url.indexOf('://') !== -1)) {
|
||||
request.url = "/api" + request.url;
|
||||
request.headers['Cache-Control'] = 'no-cache';
|
||||
}
|
||||
|
||||
return request || $q.when(request);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
}]);
|
||||
|
||||
app.run(['$rootScope', '$window', '$couchPotato', '$injector', '$state', '$http', function ($rootScope, $window, $couchPotato, $injector, $state, $http) {
|
||||
app.lazy = $couchPotato;
|
||||
|
||||
@ -30,7 +46,7 @@ app.run(['$rootScope', '$window', '$couchPotato', '$injector', '$state', '$http'
|
||||
$rootScope.user = null;
|
||||
$rootScope.loggedIn = false;
|
||||
|
||||
$http.get('/api/user')
|
||||
$http.get('/user')
|
||||
.then(function (user) {
|
||||
$rootScope.user = user;
|
||||
$rootScope.loggedIn = true;
|
||||
|
@ -12,7 +12,7 @@ define(function () {
|
||||
var pwd = user.password;
|
||||
user.password = "";
|
||||
|
||||
$http.post('/auth/password', {
|
||||
$http.post('/auth/login', {
|
||||
auth: user.auth,
|
||||
password: pwd
|
||||
}).success(function (data, status) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider, $couchPotatoProvider) {
|
||||
$stateProvider.state('login', {
|
||||
url: '/',
|
||||
url: '/login',
|
||||
pageTitle: "Sign In",
|
||||
templateUrl: "/public/html/auth/login.html",
|
||||
controller: "SignInCtrl",
|
||||
|
67
routes/auth/login.go
Normal file
67
routes/auth/login.go
Normal file
@ -0,0 +1,67 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/ansible-semaphore/semaphore/database"
|
||||
"github.com/ansible-semaphore/semaphore/models"
|
||||
"github.com/gin-gonic/gin"
|
||||
sq "github.com/masterminds/squirrel"
|
||||
)
|
||||
|
||||
func Login(c *gin.Context) {
|
||||
var login struct {
|
||||
Auth string `json:"auth" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
if err := c.Bind(&login); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
login.Auth = strings.ToLower(login.Auth)
|
||||
|
||||
q := sq.Select("*").
|
||||
From("user")
|
||||
|
||||
_, err := mail.ParseAddress(login.Auth)
|
||||
if err == nil {
|
||||
q = q.Where("email=?", login.Auth)
|
||||
} else {
|
||||
q = q.Where("username=?", login.Auth)
|
||||
}
|
||||
|
||||
query, args, _ := q.ToSql()
|
||||
fmt.Println(query, args)
|
||||
|
||||
var user models.User
|
||||
if err := database.Mysql.SelectOne(&user, query, args...); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
c.AbortWithStatus(400)
|
||||
return
|
||||
}
|
||||
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(login.Password)); err != nil {
|
||||
c.AbortWithStatus(400)
|
||||
return
|
||||
}
|
||||
|
||||
session := c.MustGet("session").(models.Session)
|
||||
session.UserID = &user.ID
|
||||
|
||||
status := database.Redis.Set("session:"+session.ID, string(session.Encode()), 7*24*time.Hour)
|
||||
if err := status.Err(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.AbortWithStatus(204)
|
||||
}
|
@ -3,6 +3,7 @@ package routes
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/ansible-semaphore/semaphore/routes/auth"
|
||||
"github.com/ansible-semaphore/semaphore/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -20,7 +21,9 @@ func Route(r *gin.Engine) {
|
||||
|
||||
api.Use(authentication)
|
||||
|
||||
// serve /api/auth
|
||||
func(api *gin.RouterGroup) {
|
||||
api.POST("/login", auth.Login)
|
||||
}(api.Group("/auth"))
|
||||
|
||||
api.Use(MustAuthenticate)
|
||||
|
||||
@ -31,6 +34,11 @@ func Route(r *gin.Engine) {
|
||||
func servePublic(c *gin.Context) {
|
||||
path := c.Request.URL.Path
|
||||
|
||||
if strings.HasPrefix(path, "/api") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(path, "/public") {
|
||||
path = "/public/html/index.html"
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/bugsnag/bugsnag-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mattbaird/gochimp"
|
||||
@ -45,8 +47,18 @@ func init() {
|
||||
flag.BoolVar(&Migration, "migrate", false, "execute migrations")
|
||||
path := flag.String("config", "", "config path")
|
||||
|
||||
var pwd string
|
||||
flag.StringVar(&pwd, "hash", "", "generate hash of given password")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if len(pwd) > 0 {
|
||||
password, _ := bcrypt.GenerateFromPassword([]byte(pwd), 11)
|
||||
fmt.Println("Generated password: ", string(password))
|
||||
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if path != nil && len(*path) > 0 {
|
||||
// load
|
||||
file, err := os.Open(*path)
|
||||
|
Loading…
Reference in New Issue
Block a user