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

带网站的电话策划公司一般怎么收费

带网站的电话,策划公司一般怎么收费,哪些网站可以做店铺推广,国内最新消息新闻目录 本节大纲 一、权限管理 1. 认证 2. 授权 二、授权核心概念 三、权限管理策略 1. 基于 URL 权限管理 权限表达式 2. 基于 方法 权限管理 EnableGlobalMethodSecurity 四、基本用法 五、原理分析 六、实战 1. 简介 2. 库表设计 3. 创建 springboot 应用 本节…

目录

本节大纲

一、权限管理

1. 认证

2. 授权

二、授权核心概念

三、权限管理策略

1. 基于 URL 权限管理

权限表达式

2. 基于 方法 权限管理

@EnableGlobalMethodSecurity

四、基本用法

五、原理分析

六、实战

1. 简介

2. 库表设计

3. 创建 springboot 应用


本节大纲

  • 什么是权限管理
  • 权限管理核心概念
  • Spring Security 权限管理策略
  • 基于 URL 地址的权限管理
  • 基于方法的权限管理
  • 实战

一、权限管理

1. 认证

身份认证,就是判断一个用户是否为合法用户的处理过程。Spring Security 中支持多种不同方式的认证,但是无

论开发者使用那种方式认证,都不会影响授权功能使用。因为 Spring Security 很好做到了认证和授权解耦。

2. 授权

授权,即访问控制,控制谁能访问哪些资源。简单的理解授权就是根据系统提前设置好的规则,给用户分配可以

访问某一个资源的权限,用户根据自己所具有权限,去执行相应操作。

二、授权核心概念

在前面学习认证过程中,我们得知认证成功之后会将当前登录用户信息保存到 Authentication 对象中,

Authentication 对象中有一个getAuthorities() 方法,用来返回当前登录用户具备的权限信息,也就是当前用户

具有权限信息。

该方法的返回值为 Collection<? extends GrantedAuthority>,

当需要进行权限判断时,就回根据集合返回权限信息调用相应方法进行判断。

那么问题来了,针对于这个返回值 GrantedAuthority 应该如何理解呢? 是角色还是权限?

我们针对于授权可以是基于角色权限管理和基于资源权限管理,从设计层面上来说,角色和权限是两个完全不同

的东西:

权限是一些具体操作,角色则是某些权限集合。

如:READ_BOOK 和 ROLE_ADMIN 是完全不同的。因此至于返回值是什么取决于你的业务设计情况:

  • 基于角色权限设计就是: 用户<=>角色<=>资源三者关系 返回就是用户的角色
  • 基于资源权限设计就是: 用户<=>权限<=>资源 三者关系 返回就是用户的权限
  • 基于角色和资源权限设计就是: 用户<=>角色<=>权限<=>资源 返回统称为用户的权限

为什么可以统称为权限,因为从代码层面角色和权限没有太大不同都是权限,特别是在 Spring Security 中,角色

和权限处理方式基本上都是一样的。唯一区别 SpringSecurity 在很多时候会自动给角色添加一个ROLE_前缀,而

权限则不会自动添加。

三、权限管理策略

Spring Security 中提供的权限管理策略主要有两种类型:

  • 基于过滤器(URL)的权限管理 (FilterSecurityInterceptor)
    • 基于过滤器的权限管理主要是用来拦截 HTTP 请求,拦截下来之后,根据 HTTP 请求地址进行权限校验。
  • 基于 AOP (方法)的权限管理   (MethodSecurityInterceptor)
    • 基于 AOP 权限管理主要是用来处理方法级别的权限问题。
      当需要调用某一个方法时,通过 AOP 将操作拦截下来,然后判断用户是否具备相关的权限。

1. 基于 URL 权限管理

  • 开发 controller
@RestController
public class DemoController {@GetMapping("/admin")public String admin() {return "admin ok";}@GetMapping("/user")public String user() {return "user ok";}@GetMapping("/getInfo")public String getInfo() {return "info ok";}
}
  • 配置授权
package com.blr.config;import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {//创建内存数据源public UserDetailsService userDetailsService() {InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();inMemoryUserDetailsManager.createUser(User.withUsername("root").password("{noop}123").roles("ADMIN").build());inMemoryUserDetailsManager.createUser(User.withUsername("win7").password("{noop}123").roles("USER").build());inMemoryUserDetailsManager.createUser(User.withUsername("lisi").password("{noop}123").roles("READ_BOOK").build());return inMemoryUserDetailsManager;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService());}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeHttpRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").hasAnyRole("USER", "ADMIN").antMatchers("/getInfo").hasRole("READ_BOOK").anyRequest().authenticated().and().formLogin().and().csrf().disable();}
}
  • 启动项目测试

权限表达式

方法

说明

hasAuthority(String authority)

当前用户是否具备指定权限

hasAnyAuthority(String... authorities)

当前用户是否具备指定权限中任意一个

hasRole(String role)

当前用户是否具备指定角色

hasAnyRole(String... roles);

当前用户是否具备指定角色中任意一个

permitAll();

放行所有请求/调用

denyAll();

拒绝所有请求/调用

isAnonymous();

当前用户是否是一个匿名用户

isAuthenticated();

当前用户是否已经认证成功

isRememberMe();

当前用户是否通过 Remember-Me 自动登录

isFullyAuthenticated();

当前用户是否既不是匿名用户又不是通过 Remember-Me 自动登录的

hasPermission(Object targetId, Object permission);

当前用户是否具备指定目标的指定权限信息

hasPermission(Object targetId, String targetType, Object permission);

当前用户是否具备指定目标的指定权限信息

2. 基于 方法 权限管理

基于方法的权限管理主要是通过 A0P 来实现的,Spring Security 中通过 MethodSecurityInterceptor 来提供相

关的实现。

不同在于 FilterSecurityInterceptor 只是在请求之前进行前置处理,MethodSecurityInterceptor 除了前置处理

外还可以进行后置处理。

前置处理就是在请求之前判断是否具备相应的权限,后置处理则是对方法的执行结果进行二次过滤。前置处理和

后置处理分别对应了不同的实现类。

@EnableGlobalMethodSecurity

EnableGlobalMethodSecurity 该注解是用来开启权限注解,用法如下:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true, jsr250Enabled=true)
public class SecurityConfig extends WebsecurityConfigurerAdapter{}
  • perPostEnabled:开启 Spring Security 提供的四个权限注解,@PostAuthorize、@PostFilter、@PreAuthorize 以及@PreFilter。
  • securedEnabled:开启 Spring Security 提供的 @Secured 注解支持,该注解不支持权限表达式
  • jsr250Enabled:开启 JSR-250 提供的注解,主要是@DenyAll、@PermitAll、@RolesAll 同样这些注解也不支持权限表达式
# 以上注解含义如下:
- @PostAuthorize: 在目前标方法执行之后进行权限校验。
- @PostFiter: 在目标方法执行之后对方法的返回结果进行过滤。
- @PreAuthorize:在目标方法执行之前进行权限校验。
- @PreFiter:在目前标方法执行之前对方法参数进行过滤。
- @Secured:访问目标方法必须具各相应的角色。
- @DenyAll:拒绝所有访问。
- @PermitAll:允许所有访问。
- @RolesAllowed:访问目标方法必须具备相应的角色。

这些基于方法的权限管理相关的注解,一般来说只要设置 prePostEnabled=true 就够用了。

四、基本用法

  • 开启注解使用
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled=true,securedEnabled=true, jsr250Enabled=true)
public class SecurityConfig extends WebsecurityConfigurerAdapter{}
  • 使用注解
@RestController
@RequestMapping("/hello")
public class AuthorizeMethodController {@PreAuthorize("hasRole('ADMIN') and authentication.name=='root'")@GetMappingpublic String hello() {return "hello";}@PreAuthorize("authentication.name==#name")@GetMapping("/name")public String hello(String name) {return "hello:" + name;}@PreFilter(value = "filterObject.id%2!=0",filterTarget = "users")@PostMapping("/users")  //filterTarget 必须是 数组  集合public void addUsers(@RequestBody List<User> users) {System.out.println("users = " + users);}@PostAuthorize("returnObject.id==1")@GetMapping("/userId")public User getUserById(Integer id) {return new User(id, "blr");}@PostFilter("filterObject.id%2==0")@GetMapping("/lists")public List<User> getAll() {List<User> users = new ArrayList<>();for (int i = 0; i < 10; i++) {users.add(new User(i, "blr:" + i));}return users;}@Secured({"ROLE_USER"}) //只能判断角色@GetMapping("/secured")public User getUserByUsername() {return new User(99, "secured");}@Secured({"ROLE_ADMIN","ROLE_USER"}) //具有其中一个即可@GetMapping("/username")public User getUserByUsername2(String username) {return new User(99, username);}@PermitAll@GetMapping("/permitAll")public String permitAll() {return "PermitAll";}@DenyAll@GetMapping("/denyAll")public String denyAll() {return "DenyAll";}@RolesAllowed({"ROLE_ADMIN","ROLE_USER"}) //具有其中一个角色即可@GetMapping("/rolesAllowed")public String rolesAllowed() {return "RolesAllowed";}
}

五、原理分析

  • ConfigAttribute 在 Spring Security 中,用户请求一个资源(通常是一个接口或者一个 Java 方法)需要的角色会被封装成一个ConfigAttribute 对象,在 ConfigAttribute 中只有一个 getAttribute方法,该方法返回一个 String 字符串,就是角色的名称。
    一般来说,角色名称都带有一个 ROLE_ 前缀,投票器 AccessDecisionVoter 所做的事情,其实就是比较用户所具各的角色和请求某个资源所需的 ConfigAtuibute 之间的关系。
  • AccesDecisionVoter 和 AccessDecisionManager 都有众多的实现类,在 AccessDecisionManager 中会换个遍历AccessDecisionVoter,进而决定是否允许用户访问,因而 AaccesDecisionVoter 和 AccessDecisionManager 两者的关系类似于AuthenticationProvider 和 ProviderManager 的关系。

六、实战

1. 简介

在前面的案例中,我们配置的 URL 拦截规则和请求 URL 所需要的权限都是通过代码来配置的,这样就比较死

板,如果想要调整访问某一个 URL 所需要的权限,就需要修改代码。

动态管理权限规则就是我们将 URL 拦截规则和访问 URI 所需要的权限都保存在数据库中,这样,在不修改源代码

的情况下,只需要修改数据库中的数据,就可以对权限进行调整。

用户<--中间表--> 角色 <--中间表--> 菜单

2. 库表设计

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for menu
-- ----------------------------
DROP TABLE IF EXISTS `menu`;
CREATE TABLE `menu` (`id` int(11) NOT NULL AUTO_INCREMENT,`pattern` varchar(128) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of menu
-- ----------------------------
BEGIN;
INSERT INTO `menu` VALUES (1, '/admin/**');
INSERT INTO `menu` VALUES (2, '/user/**');
INSERT INTO `menu` VALUES (3, '/guest/**');
COMMIT;-- ----------------------------
-- Table structure for menu_role
-- ----------------------------
DROP TABLE IF EXISTS `menu_role`;
CREATE TABLE `menu_role` (`id` int(11) NOT NULL AUTO_INCREMENT,`mid` int(11) DEFAULT NULL,`rid` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `mid` (`mid`),KEY `rid` (`rid`),CONSTRAINT `menu_role_ibfk_1` FOREIGN KEY (`mid`) REFERENCES `menu` (`id`),CONSTRAINT `menu_role_ibfk_2` FOREIGN KEY (`rid`) REFERENCES `role` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of menu_role
-- ----------------------------
BEGIN;
INSERT INTO `menu_role` VALUES (1, 1, 1);
INSERT INTO `menu_role` VALUES (2, 2, 2);
INSERT INTO `menu_role` VALUES (3, 3, 3);
INSERT INTO `menu_role` VALUES (4, 3, 2);
COMMIT;-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(32) DEFAULT NULL,`nameZh` varchar(32) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of role
-- ----------------------------
BEGIN;
INSERT INTO `role` VALUES (1, 'ROLE_ADMIN', '系统管理员');
INSERT INTO `role` VALUES (2, 'ROLE_USER', '普通用户');
INSERT INTO `role` VALUES (3, 'ROLE_GUEST', '游客');
COMMIT;-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(32) DEFAULT NULL,`password` varchar(255) DEFAULT NULL,`enabled` tinyint(1) DEFAULT NULL,`locked` tinyint(1) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of user
-- ----------------------------
BEGIN;
INSERT INTO `user` VALUES (1, 'admin', '{noop}123', 1, 0);
INSERT INTO `user` VALUES (2, 'user', '{noop}123', 1, 0);
INSERT INTO `user` VALUES (3, 'blr', '{noop}123', 1, 0);
COMMIT;-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (`id` int(11) NOT NULL AUTO_INCREMENT,`uid` int(11) DEFAULT NULL,`rid` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `uid` (`uid`),KEY `rid` (`rid`),CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user` (`id`),CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`rid`) REFERENCES `role` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of user_role
-- ----------------------------
BEGIN;
INSERT INTO `user_role` VALUES (1, 1, 1);
INSERT INTO `user_role` VALUES (2, 1, 2);
INSERT INTO `user_role` VALUES (3, 2, 2);
INSERT INTO `user_role` VALUES (4, 3, 3);
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

3. 创建 springboot 应用

  • 引入依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version>
</dependency>
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version>
</dependency>
  • 配置配置文件
server.port=8080
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/security?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root
mybatis.mapper-locations=classpath:com/blr/mapper/*.xml
mybatis.type-aliases-package=com.blr.entity
  • 创建实体类
public class User implements UserDetails {private Integer id;private String password;private String username;private boolean enabled;private boolean locked;private List<Role> roles;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return roles.stream().map(r -> new SimpleGrantedAuthority(r.getName())).collect(Collectors.toList());}@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return !locked;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return enabled;}public void setId(Integer id) {this.id = id;}public void setPassword(String password) {this.password = password;}public void setUsername(String username) {this.username = username;}public void setEnabled(boolean enabled) {this.enabled = enabled;}public void setLocked(boolean locked) {this.locked = locked;}public void setRoles(List<Role> roles) {this.roles = roles;}public Integer getId() {return id;}public List<Role> getRoles() {return roles;}
}

public class Role {private Integer id;private String name;private String nameZh;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getNameZh() {return nameZh;}public void setNameZh(String nameZh) {this.nameZh = nameZh;}
}

public class Menu {private Integer id;private String pattern;private List<Role> roles;public List<Role> getRoles() {return roles;}public void setRoles(List<Role> roles) {this.roles = roles;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getPattern() {return pattern;}public void setPattern(String pattern) {this.pattern = pattern;}
}
  • 创建 mapper 接口
@Mapper
public interface UserMapper {List<Role> getUserRoleByUid(Integer uid);User loadUserByUsername(String username);
}

@Mapper
public interface MenuMapper {List<Menu> getAllMenu();
}
  • 创建 mapper 文件
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.blr.mapper.UserMapper"><select id="loadUserByUsername" resultType="com.blr.entity.User">select *from userwhere username = #{username};</select><select id="getUserRoleByUid" resultType="com.blr.entity.Role">select r.*from role r,user_role urwhere ur.uid = #{uid}and ur.rid = r.id</select>
</mapper>

<mapper namespace="com.blr.mapper.MenuMapper"><resultMap id="MenuResultMap" type="com.blr.entity.Menu"><id property="id" column="id"/><result property="pattern" column="pattern"></result><collection property="roles" ofType="com.blr.entity.Role"><id column="rid" property="id"/><result column="rname" property="name"/><result column="rnameZh" property="nameZh"/></collection></resultMap><select id="getAllMenu" resultMap="MenuResultMap">select m.*, r.id as rid, r.name as rname, r.nameZh as rnameZhfrom menu mleft join menu_role mr on m.`id` = mr.`mid`left join role r on r.`id` = mr.`rid`</select>
</mapper>
  • 创建 service 接口
@Service
public class UserService implements UserDetailsService {private final UserMapper userMapper;@Autowiredpublic UserService(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = userMapper.loadUserByUsername(username);if (user == null) {throw new UsernameNotFoundException("用户不存在");}user.setRoles(userMapper.getUserRoleByUid(user.getId()));return user;}
}

@Service
public class MenuService {private final MenuMapper menuMapper;@Autowiredpublic MenuService(MenuMapper menuMapper) {this.menuMapper = menuMapper;}public List<Menu> getAllMenu() {return menuMapper.getAllMenu();}
}
  • 创建测试 controller
@RestController
public class HelloController {@GetMapping("/admin/hello")public String admin() {return "hello admin";}@GetMapping("/user/hello")public String user() {return "hello user";}@GetMapping("/guest/hello")public String guest() {return "hello guest";}@GetMapping("/hello")public String hello() {return "hello";}
}

  • 创建 CustomSecurityMetadataSource
@Component
public class CustomSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {private final MenuService menuService;@Autowiredpublic CustomSecurityMetadataSource(MenuService menuService) {this.menuService = menuService;}AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {String requestURI = ((FilterInvocation) object).getRequest().getRequestURI();List<Menu> allMenu = menuService.getAllMenu();for (Menu menu : allMenu) {if (antPathMatcher.match(menu.getPattern(), requestURI)) {String[] roles = menu.getRoles().stream().map(r -> r.getName()).toArray(String[]::new);return SecurityConfig.createList(roles);}}return null;}@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() {return null;}@Overridepublic boolean supports(Class<?> clazz) {return FilterInvocation.class.isAssignableFrom(clazz);}
}

  • 配置 Security 配置
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {private final CustomSecurityMetadataSource customSecurityMetadataSource;private final UserService userService;@Autowiredpublic SecurityConfig(CustomSecurityMetadataSource customSecurityMetadataSource, UserService userService) {this.customSecurityMetadataSource = customSecurityMetadataSource;this.userService = userService;}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService);}@Overrideprotected void configure(HttpSecurity http) throws Exception {ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);http.apply(new UrlAuthorizationConfigurer<>(applicationContext)).withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {@Overridepublic <O extends FilterSecurityInterceptor> O postProcess(O object) {object.setSecurityMetadataSource(customSecurityMetadataSource);object.setRejectPublicInvocations(true);return object;}});http.formLogin().and().csrf().disable();}
}
  • 启动入口类进行测试

http://www.dtcms.com/wzjs/313886.html

相关文章:

  • 网站续费管理系统百度互联网营销
  • 武汉万网站制作 费用做神马seo快速排名软件
  • 眉山网站建设公司网页设计基础
  • 做淘宝那样的网站要多少钱北京网站优化效果
  • 怎么查到网站是谁做的营业推广的目标通常是
  • 网站开发邮件服务器优化网站性能监测
  • 怎么在国外网站赚钱西安百度推广优化托管
  • 哪个网站做美食视频网站惠州网络营销
  • 怎么看别人网站是怎么做的qq群排名优化软件购买
  • 综合性电子商务网站有哪些网文网站排名
  • 连云港市建设工程质量监督站网站新手网络推广怎么干
  • 腾讯云网站建设流程河南今日头条新闻最新
  • 网站轮换图片怎么做商城推广
  • 如需手机网站建设百度关键词怎么做排名
  • 做网站jw100微信小程序开发文档
  • 个人做外贸网站打开百度网址
  • 宁晋网站建设seo优化费用
  • 苏州 规划建设局网站营业推广方案
  • 上饶网站制作韶关今日头条新闻
  • 帝国cms做下载网站培训平台
  • 腾云网建站品牌推广策划方案
  • 企业网站seo外包 sseo怎么做优化方案
  • 首码网站免费推广线上电商怎么做
  • 网站备案需要准备什么经典网络营销案例
  • 做网站引流做什么类型的网站最好厦门关键词优化企业
  • 公司网站能自己做吗百度手机助手app下载官网
  • 毕业做网站运营好吗衡水seo排名
  • 公司网站域名续费电子商务专业就业方向
  • 怎样做独立网站深圳网络营销推广中心
  • 江都建设银行网站百度不能搜的十大禁词