clone
This commit is contained in:
105
examples/auth/main.go
Normal file
105
examples/auth/main.go
Normal file
@ -0,0 +1,105 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
|
||||
mqtt "github.com/mochi-co/mqtt/server"
|
||||
"github.com/mochi-co/mqtt/server/listeners"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sigs := make(chan os.Signal, 1)
|
||||
done := make(chan bool, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
<-sigs
|
||||
done <- true
|
||||
}()
|
||||
|
||||
fmt.Println(aurora.Magenta("Mochi MQTT Server initializing..."), aurora.Cyan("TCP"))
|
||||
|
||||
server := mqtt.NewServer(nil)
|
||||
tcp := listeners.NewTCP("t1", ":1883")
|
||||
err := server.AddListener(tcp, &listeners.Config{
|
||||
Auth: &Auth{
|
||||
Users: map[string]string{
|
||||
"peach": "password1",
|
||||
"melon": "password2",
|
||||
"apple": "password3",
|
||||
},
|
||||
AllowedTopics: map[string][]string{
|
||||
// Melon user only has access to melon topics.
|
||||
// If you were implementing this in the real world, you might ensure
|
||||
// that any topic prefixed with "melon" is allowed (see ACL func below).
|
||||
"melon": {"melon/info", "melon/events"},
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
err := server.Serve()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
fmt.Println(aurora.BgMagenta(" Started! "))
|
||||
|
||||
<-done
|
||||
fmt.Println(aurora.BgRed(" Caught Signal "))
|
||||
|
||||
server.Close()
|
||||
fmt.Println(aurora.BgGreen(" Finished "))
|
||||
}
|
||||
|
||||
// Auth is an example auth provider for the server. In the real world
|
||||
// you are more likely to replace these fields with database/cache lookups
|
||||
// to check against an auth list. As the Auth Controller is an interface, it can
|
||||
// be built however you want, as long as it fulfils the interface signature.
|
||||
type Auth struct {
|
||||
Users map[string]string // A map of usernames (key) with passwords (value).
|
||||
AllowedTopics map[string][]string // A map of usernames and topics
|
||||
}
|
||||
|
||||
// Authenticate returns true if a username and password are acceptable.
|
||||
func (a *Auth) Authenticate(user, password []byte) bool {
|
||||
// If the user exists in the auth users map, and the password is correct,
|
||||
// then they can connect to the server. In the real world, this could be a database
|
||||
// or cached users lookup.
|
||||
if pass, ok := a.Users[string(user)]; ok && pass == string(password) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// ACL returns true if a user has access permissions to read or write on a topic.
|
||||
func (a *Auth) ACL(user []byte, topic string, write bool) bool {
|
||||
|
||||
// An example ACL - if the user has an entry in the auth allow list, then they are
|
||||
// subject to ACL restrictions. Only let them use a topic if it's available for their
|
||||
// user.
|
||||
if topics, ok := a.AllowedTopics[string(user)]; ok {
|
||||
for _, t := range topics {
|
||||
|
||||
// In the real world you might allow all topics prefixed with a user's username,
|
||||
// or similar multi-topic filters.
|
||||
if t == topic {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Otherwise, allow all topics.
|
||||
return true
|
||||
}
|
Reference in New Issue
Block a user