build in role permission check (#661)

diff --git a/docs/user-guides/rbac.md b/docs/user-guides/rbac.md
index bce3491..bdc782d 100644
--- a/docs/user-guides/rbac.md
+++ b/docs/user-guides/rbac.md
@@ -61,14 +61,28 @@
 ```shell script
 curl -X PUT \
   http://127.0.0.1:30100/v4/account-password \
-  -H 'Authorization: Bear eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50Ijoicm9vdCIsImV4cCI6MTU5MzMyOTE3OSwicm9sZSI6IiJ9.OR_uruuLds1wz10_J4gDEA-L9Ma_1RrHiKEA6CS-Nilv6hHB5KyhZ9_4qqf_c0iia4uKryAGHKsXUvrjOE51tz4QCXlgCmddrkYuLQsnDezXhV3TIqzdl4R_cy8h2cZo8O_b_q7eU2Iemd6x7BJE49SLgNiP5LTXCVct5Qm_GiXYTaM4dbHIJ01V-EPmNQuBr1vKdfNa8cqWtASSp9IEkFx1YpzhFacQgmfoiSGHvxQYZldQXuAh60ZXLBDexGu6jGnG39MqVNRysvHTpZRqxZWBhmEn5DeXpgKu-zlakJMjeEma4zcN-H0MumE-nMlBT5kjKWVr1DOdtOyJI6i786ZpS0wWHV4VOxpSursoKsW_XuTZCMM8LTBgdy5icCuHUXvvWXYJxPks9Pq3DcFjPlY3IuXyfokEWxGvrAF6jzglgSrNTiRkoNBKVktEapDyrpyWfktp22mhvWF6GuNoUzztxFPJblH-TXdudzWeqx-gV1lsRPSMsW8-oq6pxJfeb-b0PNM8vAIbwvv8an4T5iNMBZMz7J9NbpVCaj5eLcgfUXktyb8eWSfANhYMxY9kQN9dHZlkASAW-sjehi-rBXYJ8aCL4EbLzrYlmFWoN0z25dxvAxmWaPRQED3METYyZHvV_G4DSQf0cB2Oer_YdoRa6HWmxnTlz0HwPEq55PM' \
+  -H 'Authorization: Bear {your_token}' \
   -d '{
 	"currentPassword":"rootpwd",
 	"password":"123"
 }'
 ```
 
-### Roles TODO
-currently, you can not custom and manage any role and role policy. there is only 1 build in roles
+### create a new account by account which has admin role 
+```shell script
+curl -X POST \
+  http://127.0.0.1:30100/v4/account \
+  -H 'Accept: */*' \
+  -H 'Authorization: Bear {your_token}' \
+  -H 'Content-Type: application/json' \
+  -d '{
+	"name":"peter",
+	"password":"{strong_password}",
+	"role":"developer"
+	
+}'
+```
+### Roles 
+currently, you can not custom and manage any role and role policy. there is only 2 build in roles. rbac feature is in early development stage.
 - admin: able to do anything, including manage account, even change other account password
 - service: able to call most of API except account management.
\ No newline at end of file
diff --git a/go.mod b/go.mod
index 517f1a9..5e7d911 100644
--- a/go.mod
+++ b/go.mod
@@ -23,7 +23,7 @@
 	github.com/ghodss/yaml v1.0.0 // indirect
 	github.com/go-chassis/foundation v0.1.1-0.20191113114104-2b05871e9ec4
 	github.com/go-chassis/go-archaius v1.3.2
-	github.com/go-chassis/go-chassis v0.0.0-20200624080301-8af281f0f75b
+	github.com/go-chassis/go-chassis v0.0.0-20200709095636-48e710908928
 	github.com/go-chassis/paas-lager v1.1.1
 	github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d
 	github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
diff --git a/pkg/model/account.go b/pkg/errors/text.go
similarity index 69%
copy from pkg/model/account.go
copy to pkg/errors/text.go
index b1da8dd..a9c3e7b 100644
--- a/pkg/model/account.go
+++ b/pkg/errors/text.go
@@ -15,19 +15,12 @@
  * limitations under the License.
  */
 
-package model
+package errors
 
 const (
-	RoleAdmin   = "admin"
-	RoleAuditor = "auditor"
-)
+	ErrMsgJSON = "json is invalid"
 
-type Account struct {
-	Name            string `json:"name,omitempty"`
-	Password        string `json:"password,omitempty"`
-	Role            string `json:"role,omitempty"`
-	CurrentPassword string `json:"currentPassword,omitempty"`
-}
-type Token struct {
-	TokenStr string `json:"token,omitempty"`
-}
+	ErrMsgCreateAccount = "create account failed"
+	ErrMsgRolePerm      = "check role permissions failed"
+	ErrMsgNoPerm        = "no permission to operate"
+)
diff --git a/pkg/model/account.go b/pkg/rbacframe/account.go
similarity index 80%
rename from pkg/model/account.go
rename to pkg/rbacframe/account.go
index b1da8dd..4b32c4f 100644
--- a/pkg/model/account.go
+++ b/pkg/rbacframe/account.go
@@ -15,19 +15,29 @@
  * limitations under the License.
  */
 
-package model
+package rbacframe
 
 const (
-	RoleAdmin   = "admin"
-	RoleAuditor = "auditor"
+	RoleAdmin = "admin"
 )
 
 type Account struct {
 	Name            string `json:"name,omitempty"`
 	Password        string `json:"password,omitempty"`
 	Role            string `json:"role,omitempty"`
+	TokenExpiryTime string `json:"tokenExpiryTime,omitempty"`
 	CurrentPassword string `json:"currentPassword,omitempty"`
 }
+
 type Token struct {
 	TokenStr string `json:"token,omitempty"`
 }
+
+type Role struct {
+	Project     []string
+	Permissions map[string]*Permission
+}
+type Permission struct {
+	IDs   []string // TODO make IDs checked by rbac
+	Verbs []string
+}
diff --git a/pkg/rbacframe/api.go b/pkg/rbacframe/api.go
new file mode 100644
index 0000000..5f7c462
--- /dev/null
+++ b/pkg/rbacframe/api.go
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Package rbacframe help other component which want to use servicecomb rbac system
+package rbacframe
+
+import (
+	"context"
+	"crypto/rsa"
+	"github.com/go-chassis/go-chassis/security/token"
+)
+
+const (
+	ClaimsUser = "account"
+	ClaimsRole = "role"
+)
+
+func AccountFromContext(ctx context.Context) (*Account, error) {
+	claims := FromContext(ctx)
+	m, ok := claims.(map[string]interface{})
+	if !ok {
+		return nil, ErrInvalidCtx
+	}
+	accountNameI := m[ClaimsUser]
+	a, ok := accountNameI.(string)
+	if !ok {
+		return nil, ErrConvertErr
+	}
+	roleI := m[ClaimsRole]
+	role, ok := roleI.(string)
+	if !ok {
+		return nil, ErrConvertErr
+	}
+	account := &Account{Name: a, Role: role}
+	return account, nil
+}
+
+//RoleFromContext only return role name
+func RoleFromContext(ctx context.Context) (string, error) {
+	claims := FromContext(ctx)
+	m, ok := claims.(map[string]interface{})
+	if !ok {
+		return "", ErrInvalidCtx
+	}
+	roleI := m[ClaimsRole]
+	role, ok := roleI.(string)
+	if !ok {
+		return "", ErrConvertErr
+	}
+	return role, nil
+}
+
+//Authenticate parse a token to claims
+func Authenticate(tokenStr string, pub *rsa.PublicKey) (interface{}, error) {
+	claims, err := token.Verify(tokenStr, func(claims interface{}, method token.SigningMethod) (interface{}, error) {
+		return pub, nil
+	})
+	if err != nil {
+		return nil, err
+	}
+	return claims, nil
+}
diff --git a/pkg/rbacframe/api_test.go b/pkg/rbacframe/api_test.go
new file mode 100644
index 0000000..02b9bf2
--- /dev/null
+++ b/pkg/rbacframe/api_test.go
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rbacframe_test
+
+import (
+	"context"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
+	"github.com/go-chassis/go-chassis/security/secret"
+	"github.com/go-chassis/go-chassis/security/token"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestFromContext(t *testing.T) {
+	ctx := rbacframe.NewContext(context.TODO(), map[string]interface{}{
+		rbacframe.ClaimsUser: "root",
+		rbacframe.ClaimsRole: "admin",
+	})
+
+	c := rbacframe.FromContext(ctx)
+	claims := c.(map[string]interface{})
+	u := claims[rbacframe.ClaimsUser]
+	r := claims[rbacframe.ClaimsRole]
+	assert.Equal(t, "root", u)
+	assert.Equal(t, "admin", r)
+
+	a, err := rbacframe.AccountFromContext(ctx)
+	assert.NoError(t, err)
+	assert.Equal(t, "root", a.Name)
+	assert.Equal(t, "admin", a.Role)
+}
+
+func TestMustAuth(t *testing.T) {
+	rbacframe.Add2WhiteAPIList("/test")
+	assert.False(t, rbacframe.MustAuth("/test"))
+	assert.True(t, rbacframe.MustAuth("/auth"))
+}
+
+func TestAuthenticate(t *testing.T) {
+	pri, pub, err := secret.GenRSAKeyPair(4096)
+	assert.NoError(t, err)
+
+	to, err := token.Sign(map[string]interface{}{
+		rbacframe.ClaimsUser: "root",
+		rbacframe.ClaimsRole: "admin",
+	}, pri, token.WithSigningMethod(token.RS512))
+	assert.NoError(t, err)
+
+	_, err = rbacframe.Authenticate(to, pub)
+	assert.NoError(t, err)
+
+	_, err = rbacframe.Authenticate("token", nil)
+	assert.Error(t, err)
+}
diff --git a/server/service/rbac/context.go b/pkg/rbacframe/context.go
similarity index 85%
rename from server/service/rbac/context.go
rename to pkg/rbacframe/context.go
index 86d70c0..22b98ef 100644
--- a/server/service/rbac/context.go
+++ b/pkg/rbacframe/context.go
@@ -15,9 +15,12 @@
  * limitations under the License.
  */
 
-package rbac
+package rbacframe
 
-import "context"
+import (
+	"context"
+	"k8s.io/apimachinery/pkg/util/sets"
+)
 
 // key is an unexported type for keys defined in this package.
 // This prevents collisions with keys defined in other packages.
@@ -38,3 +41,12 @@
 	a := ctx.Value(accountKey)
 	return a
 }
+
+var whiteAPIList = sets.NewString()
+
+func Add2WhiteAPIList(path ...string) {
+	whiteAPIList.Insert(path...)
+}
+func MustAuth(url string) bool {
+	return !whiteAPIList.Has(url)
+}
diff --git a/pkg/model/account.go b/pkg/rbacframe/error.go
similarity index 68%
copy from pkg/model/account.go
copy to pkg/rbacframe/error.go
index b1da8dd..383206e 100644
--- a/pkg/model/account.go
+++ b/pkg/rbacframe/error.go
@@ -15,19 +15,17 @@
  * limitations under the License.
  */
 
-package model
+package rbacframe
 
-const (
-	RoleAdmin   = "admin"
-	RoleAuditor = "auditor"
+import (
+	"errors"
 )
 
-type Account struct {
-	Name            string `json:"name,omitempty"`
-	Password        string `json:"password,omitempty"`
-	Role            string `json:"role,omitempty"`
-	CurrentPassword string `json:"currentPassword,omitempty"`
-}
-type Token struct {
-	TokenStr string `json:"token,omitempty"`
-}
+var (
+	ErrInvalidHeader = errors.New("invalid auth header")
+	ErrNoHeader      = errors.New("should provide Authorization header")
+	ErrInvalidCtx    = errors.New("invalid context")
+
+	ErrConvertErr = errors.New(MsgConvertErr)
+	MsgConvertErr = "type convert error"
+)
diff --git a/pkg/util/common.go b/pkg/util/common.go
index 2c92e57..a876bc9 100644
--- a/pkg/util/common.go
+++ b/pkg/util/common.go
@@ -25,7 +25,3 @@
 	CtxRequestRevision  = "requestRev"
 	CtxResponseRevision = "responseRev"
 )
-
-const (
-	ErrMsgConvert = "type convert error"
-)
diff --git a/pkg/validate/matcher.go b/pkg/validate/matcher.go
new file mode 100644
index 0000000..333fd8c
--- /dev/null
+++ b/pkg/validate/matcher.go
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package validate
+
+import "unicode"
+
+type PasswordChecker struct {
+}
+
+func (p *PasswordChecker) MatchString(s string) bool {
+	var (
+		hasMinLen  = false
+		hasUpper   = false
+		hasLower   = false
+		hasNumber  = false
+		hasSpecial = false
+	)
+	if len(s) >= 8 {
+		hasMinLen = true
+	}
+	for _, char := range s {
+		switch {
+		case unicode.IsUpper(char):
+			hasUpper = true
+		case unicode.IsLower(char):
+			hasLower = true
+		case unicode.IsNumber(char):
+			hasNumber = true
+		case unicode.IsPunct(char) || unicode.IsSymbol(char):
+			hasSpecial = true
+		}
+	}
+	return hasMinLen && hasUpper && hasLower && hasNumber && hasSpecial
+}
+func (p *PasswordChecker) String() string {
+	return "password"
+}
diff --git a/pkg/validate/validator.go b/pkg/validate/validator.go
index 1720a95..6eb1650 100644
--- a/pkg/validate/validator.go
+++ b/pkg/validate/validator.go
@@ -26,8 +26,8 @@
 )
 
 type Validator struct {
-	rules map[string](*Rule)
-	subs  map[string](*Validator)
+	rules map[string]*Rule
+	subs  map[string]*Validator
 	once  sync.Once
 }
 
diff --git a/server/plugin/auth/auth.go b/server/plugin/auth/auth.go
index f55a806..19a33e2 100644
--- a/server/plugin/auth/auth.go
+++ b/server/plugin/auth/auth.go
@@ -18,12 +18,9 @@
 package auth
 
 import (
-	"errors"
 	"net/http"
 )
 
-var ErrNoHeader = errors.New("should provide Authorization header")
-
 type Auth interface {
 	Identify(r *http.Request) error
 }
diff --git a/server/plugin/auth/buildin/buidlin_test.go b/server/plugin/auth/buildin/buidlin_test.go
index e86761e..d1b5a99 100644
--- a/server/plugin/auth/buildin/buidlin_test.go
+++ b/server/plugin/auth/buildin/buidlin_test.go
@@ -18,17 +18,21 @@
 package buildin_test
 
 import (
+	"context"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 	mgr "github.com/apache/servicecomb-service-center/server/plugin"
-	"github.com/apache/servicecomb-service-center/server/plugin/auth"
 	"github.com/apache/servicecomb-service-center/server/plugin/auth/buildin"
 	"github.com/apache/servicecomb-service-center/server/plugin/discovery/etcd"
 	etcd2 "github.com/apache/servicecomb-service-center/server/plugin/registry/etcd"
 	plain "github.com/apache/servicecomb-service-center/server/plugin/security/buildin"
 	"github.com/apache/servicecomb-service-center/server/plugin/tracing/pzipkin"
 	"github.com/apache/servicecomb-service-center/server/service/rbac"
+	"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
 	"github.com/astaxie/beego"
 	"github.com/go-chassis/go-archaius"
+	"github.com/go-chassis/go-chassis/security/authr"
 	"github.com/go-chassis/go-chassis/security/secret"
+	"github.com/go-chassis/go-chassis/server/restful"
 	"github.com/stretchr/testify/assert"
 	"io/ioutil"
 	"net/http"
@@ -49,6 +53,8 @@
 
 }
 func TestTokenAuthenticator_Identify(t *testing.T) {
+	dao.DeleteAccount(context.TODO(), "root")
+	dao.DeleteAccount(context.TODO(), "non-admin")
 	t.Run("init rbac", func(t *testing.T) {
 		err := archaius.Init(archaius.WithMemorySource(), archaius.WithENVSource())
 		assert.NoError(t, err)
@@ -69,8 +75,46 @@
 	})
 	a := buildin.New()
 	ta := a.(*buildin.TokenAuthenticator)
-	r := httptest.NewRequest(http.MethodGet, "/any", nil)
-	err := ta.Identify(r)
-	t.Log(err)
-	assert.Equal(t, auth.ErrNoHeader, err)
+
+	t.Run("without auth header should failed", func(t *testing.T) {
+		r := httptest.NewRequest(http.MethodGet, "/any", nil)
+		err := ta.Identify(r)
+		t.Log(err)
+		assert.Equal(t, rbacframe.ErrNoHeader, err)
+	})
+
+	t.Run("with wrong auth header should failed", func(t *testing.T) {
+		r := httptest.NewRequest(http.MethodGet, "/any", nil)
+		r.Header.Set(restful.HeaderAuth, "Bear")
+		err := ta.Identify(r)
+		t.Log(err)
+		assert.Equal(t, rbacframe.ErrInvalidHeader, err)
+	})
+
+	t.Run("with valid header and invalid token, should failed", func(t *testing.T) {
+		r := httptest.NewRequest(http.MethodGet, "/any", nil)
+		r.Header.Set(restful.HeaderAuth, "Bear fake_token")
+		err := ta.Identify(r)
+		t.Log(err)
+		assert.Error(t, err)
+	})
+	t.Run("valid admin token, should be able to operate account", func(t *testing.T) {
+		r := httptest.NewRequest(http.MethodGet, "/v4/account", nil)
+		to, err := authr.Login(context.TODO(), "root", "root")
+		assert.NoError(t, err)
+		r.Header.Set(restful.HeaderAuth, "Bear "+to)
+		err = ta.Identify(r)
+		assert.NoError(t, err)
+	})
+	t.Run("valid normal token, should no be able to operate account", func(t *testing.T) {
+		err := dao.CreateAccount(context.TODO(), &rbacframe.Account{Name: "non-admin", Password: "123", Role: "developer"})
+		assert.NoError(t, err)
+		r := httptest.NewRequest(http.MethodGet, "/v4/account", nil)
+		to, err := authr.Login(context.TODO(), "non-admin", "123")
+		assert.NoError(t, err)
+		r.Header.Set(restful.HeaderAuth, "Bear "+to)
+		err = ta.Identify(r)
+		t.Log(err)
+		assert.Error(t, err)
+	})
 }
diff --git a/server/plugin/auth/buildin/buildin.go b/server/plugin/auth/buildin/buildin.go
index 3f597f7..d3cf120 100644
--- a/server/plugin/auth/buildin/buildin.go
+++ b/server/plugin/auth/buildin/buildin.go
@@ -18,11 +18,14 @@
 package buildin
 
 import (
+	"context"
 	"errors"
+	errorsEx "github.com/apache/servicecomb-service-center/pkg/errors"
 	"github.com/apache/servicecomb-service-center/pkg/log"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 	mgr "github.com/apache/servicecomb-service-center/server/plugin"
-	"github.com/apache/servicecomb-service-center/server/plugin/auth"
 	"github.com/apache/servicecomb-service-center/server/service/rbac"
+	"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
 	"github.com/go-chassis/go-chassis/security/authr"
 	"github.com/go-chassis/go-chassis/server/restful"
 	"net/http"
@@ -44,34 +47,48 @@
 	if !rbac.Enabled() {
 		return nil
 	}
-	if !mustAuth(req) {
+	if !rbacframe.MustAuth(req.URL.Path) {
 		return nil
 	}
 
 	v := req.Header.Get(restful.HeaderAuth)
 	if v == "" {
-		return auth.ErrNoHeader
+		return rbacframe.ErrNoHeader
 	}
 	s := strings.Split(v, " ")
 	if len(s) != 2 {
-		return errors.New("invalid auth header")
+		return rbacframe.ErrInvalidHeader
 	}
 	to := s[1]
-	//TODO rbac
+
 	claims, err := authr.Authenticate(req.Context(), to)
 	if err != nil {
 		log.Errorf(err, "authenticate request failed, %s %s", req.Method, req.RequestURI)
 		return err
 	}
-	req2 := req.WithContext(rbac.NewContext(req.Context(), claims))
+	//TODO rbac
+	m, ok := claims.(map[string]interface{})
+	if !ok {
+		log.Error("claims convert failed", rbacframe.ErrConvertErr)
+		return rbacframe.ErrConvertErr
+	}
+	role := m[rbacframe.ClaimsRole]
+	roleName, ok := role.(string)
+	if !ok {
+		log.Error("role convert failed", rbacframe.ErrConvertErr)
+		return rbacframe.ErrConvertErr
+	}
+	r := dao.GetResource(context.TODO(), req.URL.Path)
+	//TODO add verbs
+	allow, err := rbac.Allow(context.TODO(), roleName, req.URL.Query().Get(":project"), r, "")
+	if err != nil {
+		log.Error("", err)
+		return errors.New(errorsEx.ErrMsgRolePerm)
+	}
+	if !allow {
+		return errors.New(errorsEx.ErrMsgNoPerm)
+	}
+	req2 := req.WithContext(rbacframe.NewContext(req.Context(), claims))
 	*req = *req2
 	return nil
 }
-func mustAuth(req *http.Request) bool {
-	for v := range rbac.WhiteAPIList() {
-		if strings.Contains(req.URL.Path, v) {
-			return false
-		}
-	}
-	return true
-}
diff --git a/server/rest/controller/v4/auth_resource.go b/server/rest/controller/v4/auth_resource.go
index 0159693..8e0e1e6 100644
--- a/server/rest/controller/v4/auth_resource.go
+++ b/server/rest/controller/v4/auth_resource.go
@@ -20,14 +20,15 @@
 import (
 	"context"
 	"encoding/json"
-	"errors"
+	errorsEx "github.com/apache/servicecomb-service-center/pkg/errors"
 	"github.com/apache/servicecomb-service-center/pkg/log"
-	"github.com/apache/servicecomb-service-center/pkg/model"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 	"github.com/apache/servicecomb-service-center/pkg/rest"
-	util2 "github.com/apache/servicecomb-service-center/pkg/util"
 	"github.com/apache/servicecomb-service-center/server/rest/controller"
 	"github.com/apache/servicecomb-service-center/server/scerror"
+	"github.com/apache/servicecomb-service-center/server/service"
 	"github.com/apache/servicecomb-service-center/server/service/rbac"
+	"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
 	"github.com/go-chassis/go-chassis/security/authr"
 	"io/ioutil"
 	"net/http"
@@ -40,9 +41,35 @@
 func (r *AuthResource) URLPatterns() []rest.Route {
 	return []rest.Route{
 		{Method: http.MethodPost, Path: "/v4/token", Func: r.Login},
+		{Method: http.MethodPost, Path: "/v4/account", Func: r.CreateAccount},
 		{Method: http.MethodPut, Path: "/v4/account-password", Func: r.ChangePassword},
 	}
 }
+func (r *AuthResource) CreateAccount(w http.ResponseWriter, req *http.Request) {
+	body, err := ioutil.ReadAll(req.Body)
+	if err != nil {
+		log.Error("read body err", err)
+		controller.WriteError(w, scerror.ErrInternal, err.Error())
+		return
+	}
+	a := &rbacframe.Account{}
+	if err = json.Unmarshal(body, a); err != nil {
+		log.Error("json err", err)
+		controller.WriteError(w, scerror.ErrInvalidParams, errorsEx.ErrMsgJSON)
+		return
+	}
+	err = service.ValidateCreateAccount(a)
+	if err != nil {
+		controller.WriteError(w, scerror.ErrInvalidParams, err.Error())
+		return
+	}
+	err = dao.CreateAccount(context.TODO(), a)
+	if err != nil {
+		log.Error(errorsEx.ErrMsgCreateAccount, err)
+		controller.WriteError(w, scerror.ErrInternal, errorsEx.ErrMsgCreateAccount)
+		return
+	}
+}
 func (r *AuthResource) ChangePassword(w http.ResponseWriter, req *http.Request) {
 	body, err := ioutil.ReadAll(req.Body)
 	if err != nil {
@@ -50,48 +77,30 @@
 		controller.WriteError(w, scerror.ErrInternal, err.Error())
 		return
 	}
-	a := &model.Account{}
+	a := &rbacframe.Account{}
 	if err = json.Unmarshal(body, a); err != nil {
 		log.Error("json err", err)
+		controller.WriteError(w, scerror.ErrInvalidParams, errorsEx.ErrMsgJSON)
+		return
+	}
+	err = service.ValidateChangePWD(a)
+	if err != nil {
 		controller.WriteError(w, scerror.ErrInvalidParams, err.Error())
 		return
 	}
-	if a.Password == "" {
-		controller.WriteError(w, scerror.ErrInvalidParams, "new password is empty")
+	changer, err := rbacframe.AccountFromContext(req.Context())
+	if err != nil {
+		controller.WriteError(w, scerror.ErrInternal, "can not parse account info")
 		return
 	}
-	claims := rbac.FromContext(req.Context())
-	m, ok := claims.(map[string]interface{})
-	if !ok {
-		log.Error("claims convert failed", errors.New(util2.ErrMsgConvert))
-		controller.WriteError(w, scerror.ErrInvalidParams, util2.ErrMsgConvert)
-		return
-	}
-	accountNameI := m[rbac.ClaimsUser]
-	changer, ok := accountNameI.(string)
-	if !ok {
-		log.Error("claims convert failed", errors.New(util2.ErrMsgConvert))
-		controller.WriteError(w, scerror.ErrInternal, util2.ErrMsgConvert)
-		return
-	}
-	roleI := m[rbac.ClaimsRole]
-	role, ok := roleI.(string)
-	if !ok {
-		log.Error("claims convert failed", errors.New(util2.ErrMsgConvert))
-		controller.WriteError(w, scerror.ErrInternal, util2.ErrMsgConvert)
-		return
-	}
-	if role == "" {
-		controller.WriteError(w, scerror.ErrInvalidParams, "role is empty")
-		return
-	}
-	err = rbac.ChangePassword(context.TODO(), role, changer, a)
+	err = rbac.ChangePassword(context.TODO(), changer.Role, changer.Name, a)
 	if err != nil {
 		log.Error("change password failed", err)
 		controller.WriteError(w, scerror.ErrInternal, err.Error())
 		return
 	}
 }
+
 func (r *AuthResource) Login(w http.ResponseWriter, req *http.Request) {
 	body, err := ioutil.ReadAll(req.Body)
 	if err != nil {
@@ -99,7 +108,7 @@
 		controller.WriteError(w, scerror.ErrInternal, err.Error())
 		return
 	}
-	a := &model.Account{}
+	a := &rbacframe.Account{}
 	if err = json.Unmarshal(body, a); err != nil {
 		log.Error("json err", err)
 		controller.WriteError(w, scerror.ErrInvalidParams, err.Error())
@@ -116,7 +125,7 @@
 		controller.WriteError(w, scerror.ErrInternal, err.Error())
 		return
 	}
-	to := &model.Token{TokenStr: t}
+	to := &rbacframe.Token{TokenStr: t}
 	b, err := json.Marshal(to)
 	if err != nil {
 		log.Error("json err", err)
diff --git a/server/service/rbac/authr_plugin.go b/server/service/rbac/authr_plugin.go
index 50518ba..65ed1ce 100644
--- a/server/service/rbac/authr_plugin.go
+++ b/server/service/rbac/authr_plugin.go
@@ -21,6 +21,7 @@
 	"context"
 	"errors"
 	"github.com/apache/servicecomb-service-center/pkg/log"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 	"github.com/apache/servicecomb-service-center/server/service/cipher"
 	"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
 	"github.com/dgrijalva/jwt-go"
@@ -30,11 +31,6 @@
 
 var ErrUnauthorized = errors.New("wrong user name or password")
 
-const (
-	ClaimsUser = "account"
-	ClaimsRole = "role"
-)
-
 //EmbeddedAuthenticator is sc default auth plugin, RBAC data is persisted in etcd
 type EmbeddedAuthenticator struct {
 }
@@ -62,8 +58,8 @@
 			return "", err
 		}
 		tokenStr, err := token.Sign(map[string]interface{}{
-			ClaimsUser: user,
-			ClaimsRole: account.Role, //TODO more claims for RBAC, for example rule config
+			rbacframe.ClaimsUser: user,
+			rbacframe.ClaimsRole: account.Role, //TODO more claims for RBAC, for example rule config
 		},
 			secret,
 			token.WithExpTime("30m"),
@@ -77,20 +73,14 @@
 	return "", ErrUnauthorized
 }
 func (a *EmbeddedAuthenticator) Authenticate(ctx context.Context, tokenStr string) (interface{}, error) {
-	claims, err := token.Verify(tokenStr, func(claims interface{}, method token.SigningMethod) (interface{}, error) {
-		p, err := jwt.ParseRSAPublicKeyFromPEM([]byte(PublicKey()))
-		if err != nil {
-			log.Error("can not parse public key", err)
-			return nil, err
-		}
-		return p, nil
-	})
+	p, err := jwt.ParseRSAPublicKeyFromPEM([]byte(PublicKey()))
 	if err != nil {
-		log.Error("verify token failed", err)
+		log.Error("can not parse public key", err)
 		return nil, err
 	}
-	return claims, nil
+	return rbacframe.Authenticate(tokenStr, p)
 }
+
 func init() {
 	authr.Install("default", newEmbeddedAuthenticator)
 }
diff --git a/server/service/rbac/dao/account_dao.go b/server/service/rbac/dao/account_dao.go
index 71dca8f..4287949 100644
--- a/server/service/rbac/dao/account_dao.go
+++ b/server/service/rbac/dao/account_dao.go
@@ -25,7 +25,7 @@
 	"fmt"
 	"github.com/apache/servicecomb-service-center/pkg/etcdsync"
 	"github.com/apache/servicecomb-service-center/pkg/log"
-	"github.com/apache/servicecomb-service-center/pkg/model"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 	"github.com/apache/servicecomb-service-center/server/core"
 	"github.com/apache/servicecomb-service-center/server/service/kv"
 )
@@ -35,7 +35,7 @@
 
 //CreateAccount save 2 kv
 //1. account info
-func CreateAccount(ctx context.Context, a *model.Account) error {
+func CreateAccount(ctx context.Context, a *rbacframe.Account) error {
 	lock, err := etcdsync.Lock("/account-creating/"+a.Name, -1, false)
 	if err != nil {
 		return fmt.Errorf("account %s is creating", a.Name)
@@ -70,14 +70,14 @@
 	return nil
 }
 
-func GetAccount(ctx context.Context, name string) (*model.Account, error) {
+func GetAccount(ctx context.Context, name string) (*rbacframe.Account, error) {
 	key := core.GenerateAccountKey(name)
 	r, err := kv.Get(ctx, key)
 	if err != nil {
 		log.Errorf(err, "can not get account info")
 		return nil, err
 	}
-	a := &model.Account{}
+	a := &rbacframe.Account{}
 	err = json.Unmarshal(r.Value, a)
 	if err != nil {
 		log.Errorf(err, "account info is invalid")
@@ -104,7 +104,7 @@
 
 //CreateAccount save 2 kv
 //1. account info
-func EditAccount(ctx context.Context, a *model.Account) error {
+func EditAccount(ctx context.Context, a *rbacframe.Account) error {
 	key := core.GenerateAccountKey(a.Name)
 	exist, err := kv.Exist(ctx, key)
 	if err != nil {
diff --git a/server/service/rbac/dao/account_dao_test.go b/server/service/rbac/dao/account_dao_test.go
index 7d6cd22..31b3e74 100644
--- a/server/service/rbac/dao/account_dao_test.go
+++ b/server/service/rbac/dao/account_dao_test.go
@@ -19,7 +19,7 @@
 
 import (
 	"context"
-	"github.com/apache/servicecomb-service-center/pkg/model"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 	mgr "github.com/apache/servicecomb-service-center/server/plugin"
 	"github.com/apache/servicecomb-service-center/server/plugin/discovery/etcd"
 	etcd2 "github.com/apache/servicecomb-service-center/server/plugin/registry/etcd"
@@ -39,7 +39,7 @@
 
 }
 func TestAccountDao_CreateAccount(t *testing.T) {
-	_ = dao.CreateAccount(context.Background(), &model.Account{Name: "admin", Password: "pwd"})
+	_ = dao.CreateAccount(context.Background(), &rbacframe.Account{Name: "admin", Password: "pwd"})
 	t.Run("get account", func(t *testing.T) {
 		r, err := dao.GetAccount(context.Background(), "admin")
 		assert.NoError(t, err)
diff --git a/pkg/model/account.go b/server/service/rbac/dao/resource_dao.go
similarity index 63%
copy from pkg/model/account.go
copy to server/service/rbac/dao/resource_dao.go
index b1da8dd..f0b01da 100644
--- a/pkg/model/account.go
+++ b/server/service/rbac/dao/resource_dao.go
@@ -15,19 +15,22 @@
  * limitations under the License.
  */
 
-package model
+package dao
 
-const (
-	RoleAdmin   = "admin"
-	RoleAuditor = "auditor"
-)
+import "context"
 
-type Account struct {
-	Name            string `json:"name,omitempty"`
-	Password        string `json:"password,omitempty"`
-	Role            string `json:"role,omitempty"`
-	CurrentPassword string `json:"currentPassword,omitempty"`
+//TODO save to etcd
+//TODO now simply write dead code "*" to map all other API except account and role to service, should define resource for every API in future
+var resourceMap = map[string]string{
+	"/v4/account": "account",
+	"/v4/role":    "account",
+	"*":           "service",
 }
-type Token struct {
-	TokenStr string `json:"token,omitempty"`
+
+func GetResource(ctx context.Context, API string) string {
+	r, ok := resourceMap[API]
+	if !ok {
+		return resourceMap["*"]
+	}
+	return r
 }
diff --git a/pkg/model/account.go b/server/service/rbac/dao/role_dao.go
similarity index 61%
copy from pkg/model/account.go
copy to server/service/rbac/dao/role_dao.go
index b1da8dd..a31c486 100644
--- a/pkg/model/account.go
+++ b/server/service/rbac/dao/role_dao.go
@@ -15,19 +15,24 @@
  * limitations under the License.
  */
 
-package model
+package dao
 
-const (
-	RoleAdmin   = "admin"
-	RoleAuditor = "auditor"
+import (
+	"context"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 )
 
-type Account struct {
-	Name            string `json:"name,omitempty"`
-	Password        string `json:"password,omitempty"`
-	Role            string `json:"role,omitempty"`
-	CurrentPassword string `json:"currentPassword,omitempty"`
+//TODO delete dead code and use etcd
+var roleMap = map[string]*rbacframe.Role{
+	"admin": {Permissions: map[string]*rbacframe.Permission{
+		"account": {Verbs: []string{"*"}},
+		"service": {Verbs: []string{"*"}},
+	}},
+	"developer": {Permissions: map[string]*rbacframe.Permission{
+		"service": {Verbs: []string{"*"}},
+	}},
 }
-type Token struct {
-	TokenStr string `json:"token,omitempty"`
+
+func GetRole(ctx context.Context, role string) *rbacframe.Role {
+	return roleMap[role]
 }
diff --git a/server/service/rbac/decision.go b/server/service/rbac/decision.go
new file mode 100644
index 0000000..6df1206
--- /dev/null
+++ b/server/service/rbac/decision.go
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rbac
+
+import (
+	"context"
+	"github.com/apache/servicecomb-service-center/pkg/log"
+	"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
+)
+
+func Allow(ctx context.Context, role, project, resource, verbs string) (bool, error) {
+	r := dao.GetRole(ctx, role)
+	if r == nil {
+		log.Warn("empty role info")
+		return false, nil
+	}
+	ps := r.Permissions
+	if len(ps) == 0 {
+		log.Warn("role has no any permissions")
+		return false, nil
+	}
+	p, ok := ps[resource]
+	if !ok || p == nil {
+		log.Warn("role is not allowed to access resource")
+		return false, nil
+	}
+	//TODO check verbs and project
+	return true, nil
+}
diff --git a/server/service/rbac/decision_test.go b/server/service/rbac/decision_test.go
new file mode 100644
index 0000000..5dc1bce
--- /dev/null
+++ b/server/service/rbac/decision_test.go
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package rbac_test
+
+import (
+	"context"
+	"github.com/apache/servicecomb-service-center/server/service/rbac"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestAllow(t *testing.T) {
+	t.Run("admin can operate any resource", func(t *testing.T) {
+		ok, _ := rbac.Allow(context.TODO(), "admin", "default", "account", "create")
+		assert.True(t, ok)
+		ok, _ = rbac.Allow(context.TODO(), "admin", "default", "service", "create")
+		assert.True(t, ok)
+	})
+	t.Run("developer can not operate account", func(t *testing.T) {
+		ok, _ := rbac.Allow(context.TODO(), "developer", "default", "account", "create")
+		assert.False(t, ok)
+	})
+	t.Run("developer can not operate service", func(t *testing.T) {
+		ok, _ := rbac.Allow(context.TODO(), "developer", "default", "service", "create")
+		assert.True(t, ok)
+	})
+}
diff --git a/server/service/rbac/password.go b/server/service/rbac/password.go
index 604bc79..6e10702 100644
--- a/server/service/rbac/password.go
+++ b/server/service/rbac/password.go
@@ -20,15 +20,15 @@
 import (
 	"context"
 	"errors"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 
 	"github.com/apache/servicecomb-service-center/pkg/log"
-	"github.com/apache/servicecomb-service-center/pkg/model"
 	"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
 )
 
-func ChangePassword(ctx context.Context, changerRole, changerName string, a *model.Account) error {
+func ChangePassword(ctx context.Context, changerRole, changerName string, a *rbacframe.Account) error {
 	if a.Name != "" {
-		if changerRole != model.RoleAdmin { //need to check password mismatch. but admin role can change any user password without supply current password
+		if changerRole != rbacframe.RoleAdmin { //need to check password mismatch. but admin role can change any user password without supply current password
 			log.Error("can not change other account pwd", nil)
 			return ErrInputChangeAccount
 		}
@@ -65,6 +65,9 @@
 		log.Error("current pwd is wrong", nil)
 		return errors.New("can not change pwd")
 	}
+	if currentPassword == pwd {
+		return errors.New("the password can not be same as old one")
+	}
 	old.Password = pwd
 	err = dao.EditAccount(ctx, old)
 	if err != nil {
diff --git a/server/service/rbac/rbac.go b/server/service/rbac/rbac.go
index 54cf122..95f34f1 100644
--- a/server/service/rbac/rbac.go
+++ b/server/service/rbac/rbac.go
@@ -22,7 +22,7 @@
 	"crypto/rsa"
 	"errors"
 	"github.com/apache/servicecomb-service-center/pkg/log"
-	"github.com/apache/servicecomb-service-center/pkg/model"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 	"github.com/apache/servicecomb-service-center/server/service/cipher"
 	"github.com/apache/servicecomb-service-center/server/service/rbac/dao"
 	"github.com/astaxie/beego"
@@ -30,7 +30,6 @@
 	"github.com/go-chassis/go-chassis/security/authr"
 	"github.com/go-chassis/go-chassis/security/secret"
 	"io/ioutil"
-	"k8s.io/apimachinery/pkg/util/sets"
 )
 
 const (
@@ -64,6 +63,7 @@
 	}
 	readPrivateKey()
 	readPublicKey()
+	rbacframe.Add2WhiteAPIList("/health", "/version", "/v4/token")
 	log.Info("rbac is enabled")
 }
 
@@ -104,10 +104,10 @@
 	if pwd == "" {
 		log.Fatal("can not enable rbac, password is empty", nil)
 	}
-	if err := dao.CreateAccount(context.Background(), &model.Account{
+	if err := dao.CreateAccount(context.Background(), &rbacframe.Account{
 		Name:     admin,
 		Password: pwd,
-		Role:     model.RoleAdmin,
+		Role:     rbacframe.RoleAdmin,
 	}); err != nil {
 		if err == dao.ErrDuplicated {
 			log.Info("rbac is enabled")
@@ -150,12 +150,3 @@
 	}
 	return p, nil
 }
-
-var whiteAPIList = sets.NewString("/health", "/version", "/v4/token")
-
-func Add2WhiteAPIList(path string) {
-	whiteAPIList.Insert(path)
-}
-func WhiteAPIList() sets.String {
-	return whiteAPIList
-}
diff --git a/server/service/rbac/rbca_test.go b/server/service/rbac/rbca_test.go
index 805580c..6481535 100644
--- a/server/service/rbac/rbca_test.go
+++ b/server/service/rbac/rbca_test.go
@@ -20,7 +20,7 @@
 import (
 	"context"
 	"fmt"
-	"github.com/apache/servicecomb-service-center/pkg/model"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
 	mgr "github.com/apache/servicecomb-service-center/server/plugin"
 	"github.com/apache/servicecomb-service-center/server/plugin/discovery/etcd"
 	etcd2 "github.com/apache/servicecomb-service-center/server/plugin/registry/etcd"
@@ -80,7 +80,7 @@
 		fmt.Println("token:", token)
 		claims, err := authr.Authenticate(context.Background(), token)
 		assert.NoError(t, err)
-		assert.Equal(t, "root", claims.(map[string]interface{})[rbac.ClaimsUser])
+		assert.Equal(t, "root", claims.(map[string]interface{})[rbacframe.ClaimsUser])
 	})
 
 	t.Run("second time init", func(t *testing.T) {
@@ -88,16 +88,16 @@
 	})
 
 	t.Run("change pwd,admin can change any one password", func(t *testing.T) {
-		dao.CreateAccount(context.Background(), &model.Account{Name: "a", Password: "123"})
-		err := rbac.ChangePassword(context.Background(), model.RoleAdmin, "admin", &model.Account{Name: "a", Password: "1234"})
+		dao.CreateAccount(context.Background(), &rbacframe.Account{Name: "a", Password: "123"})
+		err := rbac.ChangePassword(context.Background(), rbacframe.RoleAdmin, "admin", &rbacframe.Account{Name: "a", Password: "1234"})
 		assert.NoError(t, err)
 		a, err := dao.GetAccount(context.Background(), "a")
 		assert.NoError(t, err)
 		assert.Equal(t, "1234", a.Password)
 	})
 	t.Run("change self password", func(t *testing.T) {
-		dao.CreateAccount(context.Background(), &model.Account{Name: "b", Password: "123"})
-		err := rbac.ChangePassword(context.Background(), "", "b", &model.Account{CurrentPassword: "123", Password: "1234"})
+		dao.CreateAccount(context.Background(), &rbacframe.Account{Name: "b", Password: "123"})
+		err := rbac.ChangePassword(context.Background(), "", "b", &rbacframe.Account{CurrentPassword: "123", Password: "1234"})
 		assert.NoError(t, err)
 		a, err := dao.GetAccount(context.Background(), "b")
 		assert.NoError(t, err)
diff --git a/server/service/validate.go b/server/service/validate.go
index 61d5d59..1f83ec2 100644
--- a/server/service/validate.go
+++ b/server/service/validate.go
@@ -20,17 +20,30 @@
 import (
 	"errors"
 	"github.com/apache/servicecomb-service-center/pkg/log"
+	"github.com/apache/servicecomb-service-center/pkg/rbacframe"
+	"github.com/apache/servicecomb-service-center/pkg/validate"
 	pb "github.com/apache/servicecomb-service-center/server/core/proto"
 	"reflect"
+	"regexp"
 )
 
+var createAccountValidator = &validate.Validator{}
+var changePWDValidator = &validate.Validator{}
+
+func init() {
+	var roleRegex, _ = regexp.Compile(`^$|^(admin|developer)$`)
+	var accountRegex, _ = regexp.Compile(`^[a-zA-Z]\w{5,15}$`)
+	createAccountValidator.AddRule("Name", &validate.Rule{Regexp: accountRegex})
+	createAccountValidator.AddRule("Role", &validate.Rule{Regexp: roleRegex})
+	createAccountValidator.AddRule("Password", &validate.Rule{Regexp: &validate.PasswordChecker{}})
+
+	changePWDValidator.AddRule("CurrentPassword", &validate.Rule{Min: 8})
+	changePWDValidator.AddRule("Password", &validate.Rule{Regexp: &validate.PasswordChecker{}})
+}
 func Validate(v interface{}) error {
-	if v == nil {
-		return errors.New("data is nil")
-	}
-	sv := reflect.ValueOf(v)
-	if sv.Kind() == reflect.Ptr && sv.IsNil() {
-		return errors.New("pointer is nil")
+	err := baseCheck(v)
+	if err != nil {
+		return err
 	}
 	switch t := v.(type) {
 	case *pb.CreateServiceRequest:
@@ -41,12 +54,10 @@
 		return GetServiceReqValidator().Validate(v)
 	case *pb.UpdateServicePropsRequest:
 		return UpdateServicePropsReqValidator().Validate(v)
-
 	case *pb.CreateDependenciesRequest:
 		return CreateDependenciesReqValidator().Validate(v)
 	case *pb.AddDependenciesRequest:
 		return AddDependenciesReqValidator().Validate(v)
-
 	case *pb.GetServiceTagsRequest:
 		return GetTagsReqValidator().Validate(v)
 	case *pb.AddServiceTagsRequest:
@@ -55,7 +66,6 @@
 		return UpdateTagReqValidator().Validate(v)
 	case *pb.DeleteServiceTagsRequest:
 		return DeleteTagReqValidator().Validate(v)
-
 	case *pb.GetAllSchemaRequest:
 		return GetSchemaReqValidator().Validate(v)
 	case *pb.GetSchemaRequest,
@@ -65,7 +75,6 @@
 		return ModifySchemaReqValidator().Validate(v)
 	case *pb.ModifySchemasRequest:
 		return ModifySchemasReqValidator().Validate(v)
-
 	case *pb.GetOneInstanceRequest,
 		*pb.GetInstancesRequest:
 		return GetInstanceReqValidator().Validate(v)
@@ -81,7 +90,6 @@
 		return HeartbeatReqValidator().Validate(v)
 	case *pb.UpdateInstancePropsRequest:
 		return UpdateInstancePropsReqValidator().Validate(v)
-
 	case *pb.GetServiceRulesRequest:
 		return GetRulesReqValidator().Validate(v)
 	case *pb.AddServiceRulesRequest:
@@ -90,7 +98,6 @@
 		return UpdateRuleReqValidator().Validate(v)
 	case *pb.DeleteServiceRulesRequest:
 		return DeleteRulesReqValidator().Validate(v)
-
 	case *pb.GetAppsRequest:
 		return MicroServiceKeyValidator().Validate(v)
 	default:
@@ -98,3 +105,28 @@
 		return nil
 	}
 }
+
+func baseCheck(v interface{}) error {
+	if v == nil {
+		return errors.New("data is nil")
+	}
+	sv := reflect.ValueOf(v)
+	if sv.Kind() == reflect.Ptr && sv.IsNil() {
+		return errors.New("pointer is nil")
+	}
+	return nil
+}
+func ValidateCreateAccount(a *rbacframe.Account) error {
+	err := baseCheck(a)
+	if err != nil {
+		return err
+	}
+	return createAccountValidator.Validate(a)
+}
+func ValidateChangePWD(a *rbacframe.Account) error {
+	err := baseCheck(a)
+	if err != nil {
+		return err
+	}
+	return changePWDValidator.Validate(a)
+}