当前位置: 首页 > news >正文

网站设计与网站建设a卷wordpress用cdn

网站设计与网站建设a卷,wordpress用cdn,合肥百度seo代理,网站如何做响应一. 根据用户的权限动态显示左侧菜单微服务 1.引入 后台Rbac客户端调用微服务权限验证功能主要是: 登录后显示用户名称、根据用户的权限动态显示左侧菜单,判断当前登录用户的权限 、没有权限访问则拒绝,参考[golang gin框架] 14.Gin 商城项目-RBAC管理,该微服务功能和上一节[g…一. 根据用户的权限动态显示左侧菜单微服务 1.引入 后台Rbac客户端调用微服务权限验证功能主要是: 登录后显示用户名称、根据用户的权限动态显示左侧菜单,判断当前登录用户的权限 、没有权限访问则拒绝,参考[golang gin框架] 14.Gin 商城项目-RBAC管理,该微服务功能和上一节[golang gin框架] 45.Gin商城项目-微服务实战之后台Rbac微服务之角色权限关联功能是一样的,因为controllers/admin/mainController.go的Index()方法都是要获取所有权限列表,以及当前角色拥有的权限,代码如下: func (con MainController) Index(c *gin.Context) {//获取Session里面保存的用户信息session : sessions.Default(c)userinfo : session.Get(userinfo_admin)//判断Session中的用户信息是否存在如果不存在跳转到登录页面注意需要判断 如果存在继续向下执行//session.Get获取返回的结果是一个空接口类型,所以需要进行类型断言: 判断userinfo是不是一个stringuserinfoStr, ok : userinfo.(string)if ok { // 说明是一个string//1.获取用户信息var userinfoStruct []models.Manager//把获取到的用户信息转换结构体json.Unmarshal([]byte(userinfoStr), userinfoStruct)//获取所有权限列表accessList : []models.Access{}models.DB.Where(module_id ?, 0).Preload(AccessItem, func(db *gorm.DB) *gorm.DB {return db.Order(access.sort DESC)}).Order(sort DESC).Find(accessList)//获取当前角色拥有的权限,并把权限id放在一个map对象中roleAccess : []models.RoleAccess{}models.DB.Where(role_id ?, userinfoStruct[0].RoleId).Find(roleAccess)roleAccessMap : make(map[int]int)for _, v : range roleAccess {roleAccessMap[v.AccessId] v.AccessId}//循环遍历所有权限数据,判断当前权限的id是否在角色权限的map对象中,如果是的话给当前数据加入checked属性for i : 0; i len(accessList); i { //循环权限列表if _, ok : roleAccessMap[accessList[i].Id]; ok { // 判断当前权限是否在角色权限的map对象中accessList[i].Checked true}for j : 0; j len(accessList[i].AccessItem); j { // 判断当前权限的子栏位是否在角色权限的map中if _, ok : roleAccessMap[accessList[i].AccessItem[j].Id]; ok { // 判断当前权限是否在角色权限的map对象中accessList[i].AccessItem[j].Checked true}}}c.HTML(http.StatusOK, admin/main/index.html, gin.H{username: userinfoStruct[0].Username,isSuper: userinfoStruct[0].IsSuper, // 是否超级管理员, 超级管理员显示全部accessList: accessList,})} else {c.Redirect(http.StatusFound, /admin/login)} } 2. 完善handler/rbacRole.go下的RoleAuth()方法 上面的代码和上一节的handler/rbacRole.go下的RoleAuth()方法类似,差别在于上面有排序功能,把上面排序的代码替换微服务RoleAuth()中对应的代码,然后在controllers/admin/mainController.go的Index()方法中调用一下这个微服务的RoleAuth()方法就可以了,替换后,handler/rbacRole.go下的RoleAuth()方法代码如下: //授权 func (e *RbacRole) RoleAuth(ctx context.Context, req *pb.RoleAuthRequest, res *pb.RoleAuthResponse) error {//1、获取角色id req.RoleId//获取所有权限列表accessList : []models.Access{}models.DB.Where(module_id ?, 0).Preload(AccessItem, func(db *gorm.DB) *gorm.DB {return db.Order(access.sort DESC)}).Order(sort DESC).Find(accessList)//获取当前角色拥有的权限,并把权限id放在一个map对象中roleAccess : []models.RoleAccess{}models.DB.Where(role_id ?, req.RoleId).Find(roleAccess)roleAccessMap : make(map[int]int)for _, v : range roleAccess {roleAccessMap[v.AccessId] v.AccessId}//循环遍历所有权限数据,判断当前权限的id是否在角色权限的map对象中,如果是的话给当前数据加入checked属性for i : 0; i len(accessList); i { //循环权限列表if _, ok : roleAccessMap[int(accessList[i].Id)]; ok { // 判断当前权限是否在角色权限的map对象中, 需要进行类型转换accessList[i].Checked true}for j : 0; j len(accessList[i].AccessItem); j { // 判断当前权限的子栏位是否在角色权限的map中if _, ok : roleAccessMap[int(accessList[i].AccessItem[j].Id)]; ok { // 判断当前权限是否在角色权限的map对象中accessList[i].AccessItem[j].Checked true}}}//处理数据:进行类型转换匹配操作var tempList []*pb.AccessModelfor _, v : range accessList {var tempItemList []*pb.AccessModelfor _, k : range v.AccessItem {tempItemList append(tempItemList, pb.AccessModel{Id: int64(k.Id),ModuleName: k.ModuleName,ActionName: k.ActionName,Type: int64(k.Type),Url: k.Url,ModuleId: int64(k.ModuleId),Sort: int64(k.Sort),Description: k.Description,Status: int64(k.Status),Checked: k.Checked, //注意,不要忘了角色是否有这个权限的判断AddTime: int64(k.AddTime),})}tempList append(tempList, pb.AccessModel{Id: int64(v.Id),ModuleName: v.ModuleName,ActionName: v.ActionName,Type: int64(v.Type),Url: v.Url,ModuleId: int64(v.ModuleId),Sort: int64(v.Sort),Description: v.Description,Status: int64(v.Status),AddTime: int64(v.AddTime),Checked: v.Checked, //注意,不要忘了角色是否有这个权限的判断AccessItem: tempItemList,})}res.AccessList tempListreturn nil }3. controllers/admin/mainController.go的Index()调用微服务的RoleAuth()方法,判断是否显示对应的菜单 然后在controllers/admin/mainController.go的Index()方法中调用一下这个微服务的RoleAuth()方法,代码如下: func (con MainController) Index(c *gin.Context) {//获取Session里面保存的用户信息session : sessions.Default(c)userinfo : session.Get(userinfo_admin)//判断Session中的用户信息是否存在如果不存在跳转到登录页面注意需要判断 如果存在继续向下执行//session.Get获取返回的结果是一个空接口类型,所以需要进行类型断言: 判断userinfo是不是一个stringuserinfoStr, ok : userinfo.(string)if ok { // 说明是一个string//1.获取用户信息var userinfoStruct []models.Manager//把获取到的用户信息转换结构体json.Unmarshal([]byte(userinfoStr), userinfoStruct)//调用微服务获取当前角色拥有权限菜单rbacClient : pbRbac.NewRbacRoleService(rbac, models.RbacClient)res, _ : rbacClient.RoleAuth(context.Background(), pbRbac.RoleAuthRequest{RoleId: int64(userinfoStruct[0].RoleId),})c.HTML(http.StatusOK, admin/main/index.html, gin.H{username: userinfoStruct[0].Username,accessList: res.AccessList, // 从微服务返回中获取数据isSuper: userinfoStruct[0].IsSuper, // 是否超级管理员, 超级管理员显示全部})} else {c.Redirect(http.StatusFound, /admin/login)} } 经过验证,发现没问题,这里就不再说明了,因为微服务RoleAuth()方法基本上没有发生变化,只是后台mainControllers.go的Index方法调用了而已 二.权限判断: 没有登录的用户不能进入后台管理中心 1.抽离adminAuth.go中间件代码,做成一个微服务方法 (1).proto/rbacRole.proto增加rpc MiddlewaresAuth方法 这里的权限判断: 没有登录的用户不能进入后台管理中心功能以前是放在middlewares/adminAuth.go中间件里面进行判断的,现在,把里面的逻辑代码抽离出来,做成一个微服务,先来看看adminAuth.go中间件里面的代码: package middlewares//中间件: 作用: 在执行路由之前或者之后进行相关逻辑判断import (encoding/jsonfmtgithub.com/gin-contrib/sessionsgithub.com/gin-gonic/gingopkg.in/ini.v1goshop/modelsnet/httposstrings )func InitAdminAuthMiddleware(c *gin.Context) {//权限判断: 没有登录的用户不能进入后台管理中心//1、获取Url访问的地址//当地址后面带参数时:,如: admin/captcha?t0.8706946438889653,需要处理//strings.Split(c.Request.URL.String(), ?): 把c.Request.URL.String()请求地址按照?分割成切片pathname : strings.Split(c.Request.URL.String(), ?)[0]//2、获取Session里面保存的用户信息session : sessions.Default(c)userinfo : session.Get(userinfo_admin)//3、判断Session中的用户信息是否存在如果不存在跳转到登录页面注意需要判断 如果存在继续向下执行//session.Get获取返回的结果是一个空接口类型,所以需要进行类型断言: 判断userinfo是不是一个stringuserinfoStr, ok : userinfo.(string)if ok { // 说明是一个stringvar userinfoStruct []models.Manager//把获取到的用户信息转换结构体err : json.Unmarshal([]byte(userinfoStr), userinfoStruct)if err ! nil || !(len(userinfoStruct) 0 userinfoStruct[0].Username ! ) {if pathname ! /admin/login pathname ! /admin/dologin pathname ! /admin/captcha {//跳转到登录页面c.Redirect(http.StatusFound, /admin/login)}} else { //表示用户登录成功//获取当前访问的URL对应的权限id,判断权限id是否在角色对应的权限中// strings.Replace 字符串替换urlPath : strings.Replace(pathname, /admin/, , 1)//排除权限判断:不是超级管理员并且不在相关权限内if userinfoStruct[0].IsSuper 0 !excludeAuthPath(/ urlPath){//判断用户权限:当前用户权限是否可以访问url地址//获取当前角色拥有的权限,并把权限id放在一个map对象中roleAccess : []models.RoleAccess{}models.DB.Where(role_id ?, userinfoStruct[0].RoleId).Find(roleAccess)roleAccessMap : make(map[int]int)for _, v : range roleAccess {roleAccessMap[v.AccessId] v.AccessId}//实例化accessaccess : models.Access{}//查询权限idmodels.DB.Where(url ? , urlPath).Find(access)//判断权限id是否在角色对应的权限中if _, ok : roleAccessMap[access.Id]; !ok {c.String(http.StatusOK, 没有权限)c.Abort() // 终止程序}}}} else {//4、如果Session不存在判断当前访问的URl是否是login doLogin captcha如果不是跳转到登录页面如果是不行任何操作//说明用户没有登录//需要排除到不需要做权限判断的路由if pathname ! /admin/login pathname ! /admin/dologin pathname ! /admin/captcha {//跳转到登录页面c.Redirect(http.StatusFound, /admin/login)}} }//排除权限判断的方法 func excludeAuthPath(urlPath string) bool {//加载配置文件cfg, err : ini.Load(./conf/app.ini)if err ! nil {fmt.Printf(Fail to read file: %v, err)os.Exit(1)}//获取需要排除的地址excludeAuthPath : cfg.Section().Key(excludeAuthPath).String()//拆分字符串成为一个切片excludeAuthPathSlice : strings.Split(excludeAuthPath, ,)//判断传入的地址是否在排除地址内for _, v : range excludeAuthPathSlice {if v urlPath {return true}}return false }从上面代码中,可以看出:当用户登录成功后,才需要判断要访问的url对应的权限id是否在对应角色的权限中,故构建微服务方法时,需要传入要访问的urlPath,以及角色id,这里把该微服务方法放到rbacRole这个微服务中,所以,在server端的proto/rbacRole.proto下的service RbacRole下增加rpc方法,如下: //权限判断:获取当前访问的URL对应的权限id,判断权限id是否在角色对应的权限中 rpc MiddlewaresAuth(MiddlewaresAuthRequest) returns (MiddlewaresAuthResponse) {} 然后实现上面rpc方法: //权限判断:角色是否有访问urlPath的权限,请求参数 message MiddlewaresAuthRequest{int64 roleId1;string urlPath2; } //权限判断:响应参数 是否具有该访问权限 message MiddlewaresAuthResponse{bool hasPermission1; } 完整代码如下:  syntax proto3;package rbac;option go_package ./proto/rbacRole;//角色管理 service RbacRole {//获取角色rpc方法: 请求参数RoleGetRequest, 响应参数RoleGetResponserpc RoleGet(RoleGetRequest) returns (RoleGetResponse) {}//增加角色rpc方法: 请求参数RoleAddRequest, 响应参数RoleAddResponserpc RoleAdd(RoleAddRequest) returns (RoleAddResponse) {}//编辑角色rpc方法: 请求参数RoleEditRequest, 响应参数RoleEditResponserpc RoleEdit(RoleEditRequest) returns (RoleEditResponse) {}//删除角色rpc方法: 请求参数RoleDeleteRequest, 响应参数RoleDeleteResponserpc RoleDelete(RoleDeleteRequest) returns (RoleDeleteResponse) {}//授权rpc RoleAuth(RoleAuthRequest) returns (RoleAuthResponse) {}//授权提交rpc RoleDoAuth(RoleDoAuthRequest) returns (RoleDoAuthResponse) {}//权限判断:获取当前访问的URL对应的权限id,判断权限id是否在角色对应的权限中rpc MiddlewaresAuth(MiddlewaresAuthRequest) returns (MiddlewaresAuthResponse) {} }//角色相关model message RoleModel{int64 id1;string title2;string description3;int64 status4;int64 addTime 5; }//权限相关模型:参考models/access.go message AccessModel{int64 id1;string moduleName 2;string actionName3;int64 type4;string url5;int64 moduleId6;int64 sort 7;string description8;int64 status9;int64 addTime10;bool checked11;repeated AccessModel accessItem12; }//获取角色请求参数 message RoleGetRequest{//角色idint64 id 1; }//获取角色响应参数 message RoleGetResponse{//角色model切片repeated RoleModel roleList1; }//增加角色请求参数 message RoleAddRequest{//角色名称string title1;//说明string description2;//状态int64 status3;//增加时间int64 addTime 4; }//增加角色响应参数 message RoleAddResponse{//是否增加成功bool success1;//返回状态说明string message2; }//编辑角色请求参数 message RoleEditRequest{//角色idint64 id1;//角色名称string title2;//说明string description3;//状态int64 status4;//增加时间int64 addTime 5; }//编辑角色响应参数 message RoleEditResponse{ //是否编辑成功bool success1;//返回状态说明string message2; }//删除角色请求参数 message RoleDeleteRequest{//角色idint64 id1; }//删除角色响应参数 message RoleDeleteResponse{ //是否删除成功bool success1;//返回状态说明string message2; }//角色授权参数 message RoleAuthRequest{int64 roleId1; } //角色授权响应参数 message RoleAuthResponse{repeated AccessModel accessList1; }//角色授权提交参数 message RoleDoAuthRequest{int64 roleId1;repeated string accessIds2; }//角色授权提交响应参数 message RoleDoAuthResponse{bool success1;string message2; }//权限判断:角色是否有访问urlPath的权限,请求参数 message MiddlewaresAuthRequest{int64 roleId1;string urlPath2; } //权限判断:响应参数 是否具有该访问权限 message MiddlewaresAuthResponse{bool hasPermission1; } (2).更新proto文件夹下对应rbacRole的方法 运行命令protoc --proto_path. --micro_out. --go_out:. proto/rbacRole.proto更新proto下的文件 (3).handler/rbacRole.go下实现上面的rpc MiddlewaresAuth方法 把中间件middlewares/adminAuth.go中判断用户权限相关代码抽离出来,做成一个MiddlewaresAuth()微服务方法,代码如下: //权限判断 func (e *RbacRole) MiddlewaresAuth(ctx context.Context, req *pb.MiddlewaresAuthRequest, res *pb.MiddlewaresAuthResponse) error {//判断用户权限:当前用户权限是否可以访问url地址// 1、根据角色获取当前角色的权限列表,然后把权限id放在一个map类型的对象里面roleAccess : []models.RoleAccess{}models.DB.Where(role_id?, req.RoleId).Find(roleAccess)roleAccessMap : make(map[int]int)for _, v : range roleAccess {roleAccessMap[v.AccessId] v.AccessId}// 2、获取当前访问的url对应的权限id 判断权限id是否在角色对应的权限// pathname /admin/manageraccess : models.Access{}models.DB.Where(url ?, req.UrlPath).Find(access)//3、判断当前访问的url对应的权限id 是否在权限列表的id中if _, ok : roleAccessMap[int(access.Id)]; !ok {res.HasPermission false} else {res.HasPermission true}return nil }2.项目端中间件adminAuth.go调用上面微服务方法,进行权限判断 (1).复制server端proto下rbacRole.go以及rbacRole文件夹到项目的proto下 因为修改了server中的rbacRole.proto,需要同步 (2).在项目的middlewares/adminAuth.go中间件中调用权限判断微服务方法 package middlewares//中间件: 作用: 在执行路由之前或者之后进行相关逻辑判断import (encoding/jsonfmtgithub.com/gin-contrib/sessionsgithub.com/gin-gonic/gingopkg.in/ini.v1goshop/modelspbRbac goshop/proto/rbacRolenet/httposcontextstrings )func InitAdminAuthMiddleware(c *gin.Context) {//权限判断: 没有登录的用户不能进入后台管理中心//1、获取Url访问的地址//当地址后面带参数时:,如: admin/captcha?t0.8706946438889653,需要处理//strings.Split(c.Request.URL.String(), ?): 把c.Request.URL.String()请求地址按照?分割成切片pathname : strings.Split(c.Request.URL.String(), ?)[0]//2、获取Session里面保存的用户信息session : sessions.Default(c)userinfo : session.Get(userinfo_admin)//3、判断Session中的用户信息是否存在如果不存在跳转到登录页面注意需要判断 如果存在继续向下执行//session.Get获取返回的结果是一个空接口类型,所以需要进行类型断言: 判断userinfo是不是一个stringuserinfoStr, ok : userinfo.(string)if ok { // 说明是一个stringvar userinfoStruct []models.Manager//把获取到的用户信息转换结构体err : json.Unmarshal([]byte(userinfoStr), userinfoStruct)if err ! nil || !(len(userinfoStruct) 0 userinfoStruct[0].Username ! ) {if pathname ! /admin/login pathname ! /admin/dologin pathname ! /admin/captcha {//跳转到登录页面c.Redirect(http.StatusFound, /admin/login)}} else { //表示用户登录成功//获取当前访问的URL对应的权限id,判断权限id是否在角色对应的权限中// strings.Replace 字符串替换urlPath : strings.Replace(pathname, /admin/, , 1)//排除权限判断:不 是超级管理员并且不在相关权限内if userinfoStruct[0].IsSuper 0 !excludeAuthPath(/ urlPath){//判断用户权限:当前用户权限是否可以访问url地址//调用微服务进行权限判断rbacClient : pbRbac.NewRbacRoleService(rbac, models.RbacClient)res, _ : rbacClient.MiddlewaresAuth(context.Background(), pbRbac.MiddlewaresAuthRequest{RoleId: int64(userinfoStruct[0].RoleId),UrlPath: urlPath,})//3、判断当前访问的url对应的权限id 是否在权限列表的id中if !res.HasPermission {c.String(200, 没有权限)c.Abort()}//获取当前角色拥有的权限,并把权限id放在一个map对象中//roleAccess : []models.RoleAccess{}//models.DB.Where(role_id ?, userinfoStruct[0].RoleId).Find(roleAccess)//roleAccessMap : make(map[int]int)//for _, v : range roleAccess {// roleAccessMap[v.AccessId] v.AccessId//}实例化access//access : models.Access{}查询权限id//models.DB.Where(url ? , urlPath).Find(access)判断权限id是否在角色对应的权限中//if _, ok : roleAccessMap[access.Id]; !ok {// c.String(http.StatusOK, 没有权限)// c.Abort() // 终止程序//}}}} else {//4、如果Session不存在判断当前访问的URl是否是login doLogin captcha如果不是跳转到登录页面如果是不行任何操作//说明用户没有登录//需要排除到不需要做权限判断的路由if pathname ! /admin/login pathname ! /admin/dologin pathname ! /admin/captcha {//跳转到登录页面c.Redirect(http.StatusFound, /admin/login)}} }//排除权限判断的方法 func excludeAuthPath(urlPath string) bool {//加载配置文件cfg, err : ini.Load(./conf/app.ini)if err ! nil {fmt.Printf(Fail to read file: %v, err)os.Exit(1)}//获取需要排除的地址excludeAuthPath : cfg.Section().Key(excludeAuthPath).String()//拆分字符串成为一个切片excludeAuthPathSlice : strings.Split(excludeAuthPath, ,)//判断传入的地址是否在排除地址内for _, v : range excludeAuthPathSlice {if v urlPath {return true}}return false }(3).验证上面的微服务方法是否正确 启动consul以及各个微服务,以及项目,登录后台,进行权限访问,发现该微服务方法没问题 三. Rbac微服务数据库抽离  1.抽离rbac相关数据表 目前项目使用的数据库是同一个数据库:ginshop,rbac微服务的数据库配置见server下rbac/conf/app.ini配置文件,相关配置如下: app_name rbac # possible values: DEBUG, INFO, WARNING, ERROR, FATAL[mysql] ip 127.0.0.1 port 3306 user root password 123456 database ginshop[consul] addr localhost:8082所以,这里举例说明抽离数据库:把rbac微服务相关数据表抽离出来,独立一个数据库,创建一个新的数据库ginshoprbac,然后把rbac相关的数据表(access,manager,role,role_access)抽离到ginshoprbac数据库中,当然,在抽离数据表之前,一定要记得备份  2.修改app.ini配置 抽离了rbac相关数据库,那么就要数据配置app.ini,修改后的配置如下: app_name rbac # possible values: DEBUG, INFO, WARNING, ERROR, FATAL[mysql] ip 127.0.0.1 port 3306 user root password 123456 database ginshoprbac[consul] addr localhost:8082 3.删除客户端rbac相关model 因为使用的是rbac微服务了,所以原来项目客户端中的model就没用了,删除无用的model,然后测试rbac微服务功能是否正确,这里删除client下model中的access.go,role.go,roleAccess.go,修改manager.go(manager.go模型还在使用),修改后的manager.go代码如下: package models//管理员表type Manager struct { // 结构体首字母大写, 和数据库表名对应, 默认访问数据表users, 可以设置访问数据表的方法Id intUsername stringPassword stringMobile stringEmail stringStatus intRoleId intAddTime intIsSuper int }修改完后,重启后台客户端,以及rbac微服务端,测试,发现没有问题,说明抽离rbac微服务数据表没有问题         好了,到这里,项目微服务相关实战内容就到这里了,查看更多文章,请看主页 [上一节]wiefuw[golang gin框架] 45.Gin商城项目-微服务实战之后台Rbac微服务之角色权限关联
http://www.zqtcl.cn/news/897830/

相关文章:

  • 成都成华网站建设小程序开发网上商城
  • 企业网站建设的重要性和必要性深圳设计网站排行
  • 山西省网站建设河南省考生服务平台官网
  • 做水产的都用什么网站wordpress 前端登陆
  • 商务网站建设网站开发一个软件开发的流程
  • 网站建设电脑和手机有区别吗公众号登录微信入口
  • 天津市建设监理协会网站三亚网络网站建设
  • 义乌进货网平台北京网优化seo优化公司
  • 在网站上放广告网站建设流程效果
  • 腾讯云学生机做网站济南网站改版
  • 开封市做网站的公司wordpress无法映射
  • 网站构建工具wordpress 主题授权
  • 大型网站开发 赚钱宁夏网站建设优化
  • 通过ip访问网站需要怎么做博客的网站页面设计
  • 高明做网站软件开发工程师是前端还是后端
  • 利用html5 监控网站性能如何能快速搜到新做网站链接
  • 做网站需要看那几点seo是什么职业岗位
  • 做游戏网站需要哪些许可100个免费推广网站下载
  • 网站管理系统是什么马鞍山网站建设制作公司
  • 设计学网站网络工程专业毕业生设计
  • 成都网站建设有名的国外优质设计网站
  • seo基础培训教程seo百度关键词优化软件
  • 西安响应式网站青岛网站制作哪里有
  • 政务服务网站建设合肥seo排名扣费
  • 郑州做网站的大公司无锡网站程序
  • 打开网站是空白页面营销型网站建设应该考虑哪些因素
  • 做网站开麻烦吗个人网站备案网站名称
  • 瑞诺国际做外贸网站好吗网站端和移动端分开建设域名一样么
  • 如何网站点击率网站程序开发技术
  • 深圳网站建设售后服务怎样.net网站开发简介