Using Casbin to implement role-based HTTP permission control in the Go language

Source: Internet
Author: User
Tags sprintf
This is a creation in Article, where the information may have evolved or changed. Identity authentication and authorization are critical to the security of your Web application. Recently, I completed my first formal Web application with Go, and this article is part of what I learned in this process. In this article, our focus is on how to use the Open source Casbin library for HTTP permission control in a Web application. At the same time, in the sample code we used the SCS library for session management. The following example is very basic, and hopefully it shows how to implement permissions control in Go Web applications as much as possible. To focus more on demonstrating the use of casbin, we try to simplify the business logic (e.g., login without password). Let's have a look! Note: Please do not use the case code shown in the production environment, which focuses on clarity rather than security. # # Build First, we create a user model and implement the appropriate method: ' Gotype User struct {ID intname stringrole string}type Users []userfunc (U Users) Exists (ID int) bool {...} Func (U Users) findbyname (name string) (User, error) {...} Then configure the required files for Casbin. Here we need a configuration file and a policy file. The configuration file uses the PERM meta-model. PERM represents policy, effect (Effect), request, and Match (matchers). In the auth_model.conf configuration file There is the following: "' [request_definition]r = Sub, obj, act[policy_definition]p = Sub, obj, Act[policy_effect] E = Some (where (p.eft = = Allow)) [matchers]m = R.sub = = P.sub && keymatch (r.obj, P.obj) && (r.act = p.act || P.act = = "*") "which defines the request and policy to represent the subject, object and action. In this case, the principal represents the user role, the object represents the access path, and the action represents the request method (example: GET, POST, etc.). The match defines how the policy is matched, either by directly defining the principal, or by using a KEYMATC-likeH such a helper method, it can also match wildcard characters. Casbin is actually much more powerful than this simple example, and you can define a variety of custom functions declaratively to achieve the ease of switching and maintaining the authentication configuration. In terms of security, I usually choose the simplest solution, because when the system begins to become complex and difficult to maintain, errors begin to occur. In this example, the policy file is a simple CSV file that describes which roles can access which paths, and so on. The Policy.csv file format is as follows: "' p, admin,/*, *p, Anonymous,/login, *p, member,/logout, *p, member,/member/*, *" This configuration file is very simple. In this example, we simply define the admin role to have access to all content, and the member role can access the paths and logout paths that begin with/member/, and unauthenticated users can log in. The benefit of this form is that even if the application has many rules and user roles, it is still maintainable. # # Execution Let's start with the main function, configure everything, and start the HTTP server: ' Gofunc main () {//Setup Casbin auth rulesauthenforcer, err: = Casbin. Newenforcersafe ("./auth_model.conf", "./policy.csv") if err! = Nil {log. Fatal (ERR)}//Setup session Storeengine: = Memstore. New (* time. Minute) SessionManager: = Session. Manage (engine, session.) IdleTimeout (30*time. Minute), session. Persist (True), session. Secure (TRUE))//Setup UsersUsers: = Createusers ()//Setup Routesmux: = http. Newservemux () Mux. Handlefunc ("/login", Loginhandler (Users)) Mux. Handlefunc ("/logout", Logouthandler ()) Mux. Handlefunc ("/member/current", CurrentmemberhandLer ()) Mux. Handlefunc ("/member/role", Memberrolehandler ()) Mux. Handlefunc ("/admin/stuff", Adminhandler ()) log. Print ("Server started on localhost:8080") log. Fatal (http. Listenandserve (": 8080", SessionManager (authorization. Authorizer (Authenforcer, users) (MUX))} "There are a few things to note here, usually, we need to configure authentication rules, session management, users, HTTP processing methods, start HTTP servers, and use authentication middleware and The session manager wraps the route. We analyze the process above. First, we created a casbin actuator with the auth_model.conf and policy.csv above. If something goes wrong, shut down the service because there may be an error in the authentication rule. The second step is to set up the session manager. We created a memory session store with a 30-minute timeout and a session manager with a secure cookie store. The Createusers function creates three different users whose user roles are as follows: "' Gofunc createusers () model. Users {users: = model. Users{}users = Append (users, model. User{id:1, Name: "admin", Role: "Admin"}) users = Append (users, model. User{id:2, Name: "Sabine", Role: "Member"}) users = Append (users, model. User{id:3, Name: "Sepp", Role: "Member"}) return users} "in practice, we use the database to store user data, in this case we use the list above for convenience. Next is the way to log in and out: "' Gofunc Loginhandler (Users model. Users) http. Handlerfunc {return HTTP. Handlerfunc (Func (w http. Responsewriter, R *http. Request) {Name: = R.postformvalue ("name") User, Err: = Users. Findbyname (name) if err! = Nil {writeerror (http. Statusbadrequest, "Wrong_credentials", W, err) return}//setup sessionif Err: = Session. Regeneratetoken (R); Err! = Nil {writeerror (http. Statusinternalservererror, "ERROR", W, err) return}session. Putint (R, "UserID", user.id) session. Putstring (R, "role", user.) Role) writesuccess ("SUCCESS", W)})}func Logouthandler () http. Handlerfunc {return HTTP. Handlerfunc (Func (w http. Responsewriter, R *http. Request) {If err: = Session. Renew (R); Err! = Nil {writeerror (http. Statusinternalservererror, "ERROR", W, err) return}writesuccess ("SUCCESS", W)})} "for login, we get the user name from the request, check if the user exists, A new session is created, and the user role and ID are stored in the session. For logoff, we create a new empty session and delete the old session from the session store and log off the user. Next, we define several processing functions to test the implementation of the application by returning the user ID and role. The endpoints of these processing functions are protected by the Casbin defined by the Policy.csv file above. "' Gofunc Currentmemberhandler () http. Handlerfunc {return HTTP. Handlerfunc (Func (w http. Responsewriter, R *http. Request) {uid, err: = Session. GetInt (R, "UserID") if err! = Nil {writeerror (http. Statusinternalservererror, "ERROR", W, err) return}writesuccess (FMT. Sprintf ("User with ID:%d", UID), W)})}func Memberrolehandler () http. Handlerfunc {return HTTP. Handlerfunc (Func (w http. Responsewriter, R *http. Request) {role, err: = Session. GetString (R, "role") if err! = Nil {writeerror (http. Statusinternalservererror, "ERROR", W, err) return}writesuccess (FMT. Sprintf ("User with Role:%s", Role), W)})}func Adminhandler () http. Handlerfunc {return HTTP. Handlerfunc (Func (w http. Responsewriter, R *http. Request) {writesuccess ("I ' m an admin!", W)})} ' we can pass the session. GetInt and session. GetString to get the value in the current session. In order for the authentication mechanism to really protect the processing function, we need to implement a authentication middleware to encapsulate the routing. "' Gofunc Authorizer (e *casbin. Enforcer, users model. Users) func (next http. Handler) http. Handler {return func (next http. Handler) http. Handler {fn: = func (w http). Responsewriter, R *http. Request) {role, err: = Session. GetString (R, "role") if err! = Nil {writeerror (http. Statusinternalservererror, "ERROR", W, err) return}if role = = "" {role = "anonymous"}//if it ' s a member, check if the user still existsif role = = "Member" {UID , err: = Session. GetInt (R, "UserID") if err! = Nil {writeerror (http. Statusinternalservererror, "ERROR", W, err) return}exists: = Users. Exists (UID) if!exists {writeerror (http. Statusforbidden, "FORBIDDEN", W, errors. New ("User does not Exist")) return}}//Casbin rule enforcingres, err: = E.enforcesafe (role, R.url. Path, R.method) if err! = Nil {writeerror (http. Statusinternalservererror, "ERROR", W, err) return}if res {next. Servehttp (W, R)} else {Writeerror (http. Statusforbidden, "FORBIDDEN", W, errors. New ("Unauthorized")) Return}}return http. Handlerfunc (FN)}} "authentication middleware with Casbin rule executor and user as parameters. First, it gets the role of the requesting user from the session. If the user does not have a role, set as anonymous role, otherwise, if the user role is member, we will be in session Useid and the user list is compared to determine whether the user is legitimate. After these preliminary checks, we can pass the user role, request path, and request method to the Casbin executor, which determines whether the user with that role (subject) is allowed access to the resource specified by the request method (action) and the path (object). If the checksum fails, 403 is returned, and if passed, the wrapper's HTTP handler is invoked, allowing the user to access the requested resource. As mentioned in the main function, the session manager and the authentication device are routed into thePackaged, so every request requires this middleware to ensure security. We can test the effect by logging in to different users, using curl or postman to access the above processing functions. # # Conclusion I have used casbin in a medium-sized Web application production environment and am very satisfied with its maintainability and stability. Can look at its documentation, Casbin is a very powerful authentication tool that provides a large number of access control models in a declarative manner. This article is designed to showcase the power of Casbin and SCs and to showcase the simplicity and clarity of the Go web app. Resources:-[code] (https://github.com/zupzup/casbin-http-role-example)-[Casbin] (Https://github.com/casbin/casbin)-[SCS] ( HTTPS://GITHUB.COM/ALEXEDWARDS/SCS)

via:https://zupzup.org/casbin-http-role-auth/

Author: Mario Translator: linyy1991 proofreading: Rxcai

This article by GCTT original compilation, go language Chinese network honor launches

This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove

3,565 reads ∙2 likes
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.