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

2个女人做暧暧网站做热饮店网站

2个女人做暧暧网站,做热饮店网站,国家企业官方网站查询系统,贵州网站开发公司目录 一、回顾一下 二、security使用 2.1 覆盖掉默认配置「自定义配置」 2.2 如何自定义认证 2.3 纯纯自定义 2.4 jwt 2.5 官网认证流程 2.6 RBAC模型 4.1. 创建表结构 2.7 如何实现权限流程 一、回顾一下 security干啥的? 认证和授权 使用方式 引入依赖, 基于spri…目录 一、回顾一下 二、security使用 2.1 覆盖掉默认配置「自定义配置」 2.2 如何自定义认证 2.3 纯纯自定义 2.4 jwt 2.5 官网认证流程 2.6 RBAC模型 4.1. 创建表结构 2.7 如何实现权限流程 一、回顾一下 security干啥的? 认证和授权 使用方式 引入依赖, 基于spring boot的下的使用. spring-boot-starter-security, 直接可以使用了. 观察一下 姿源分类 受保护的资源, 需要认证 公共方式, 不需要认证. 当我们把security引入到项目当中的时候,我们去访问一下受保护的资源,会弹出一个默认的一个登录界面.用户名称默认的是: user, 密码随机生成的.通过uuid生成的.如果认证成功,则直接跳转到要访问的接口. 基本原理 SecurityAutoConfiguration, spring security自动配置类.默认配置.如果我们啥也不干,则直接走默认配置.界面了,用户名称和密码都是默认生成的. 如果想要覆盖掉默认配置,则我们用两种方案. 继承一个类WebSecurityConfigurerAdapter, 重写方法. 将SecurityFilterChain放到容器当中. /*** {link Condition} for* {link ConditionalOnDefaultWebSecurity ConditionalOnDefaultWebSecurity}.** author Phillip Webb*/ class DefaultWebSecurityCondition extends AllNestedConditions { ​DefaultWebSecurityCondition() {super(ConfigurationPhase.REGISTER_BEAN);} ​ConditionalOnClass({ SecurityFilterChain.class, HttpSecurity.class })static class Classes { ​} ​// 当IoC容器当中没有WebSecurityConfigurerAdapter.class, SecurityFilterChain.class 这两个类的对象// 则默认生效,否则默认配置不生效.ConditionalOnMissingBean({ WebSecurityConfigurerAdapter.class, SecurityFilterChain.class })static class Beans { ​} ​ } 默认的配置类 SecurityProperties ConfigurationProperties(prefix spring.security) public class SecurityProperties {} 对认证资源进行配置 可以针对某一些资源,不进行认证, 默认是都进行认证的. 此时我们就覆盖掉默认配置. 二、security使用 2.1 覆盖掉默认配置「自定义配置」 public HttpSecurity authorizeRequests(CustomizerExpressionUrlAuthorizationConfigurerHttpSecurity.ExpressionInterceptUrlRegistry authorizeRequestsCustomizer)throws Exception {ApplicationContext context getContext();authorizeRequestsCustomizer.customize(getOrApply(new ExpressionUrlAuthorizationConfigurer(context)).getRegistry());return HttpSecurity.this; } 认证成功之后的处理: public final T successHandler(AuthenticationSuccessHandler successHandler) {this.successHandler successHandler;return getSelf(); } package com.tingyi.configs; ​ import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.core.Authentication; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; ​ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; ​ /*** author 听忆*/ Configuration public class SecurityConfig { ​Beanpublic SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {return http.authorizeRequests(authorize -authorize.mvcMatchers(/tom).permitAll().anyRequest().authenticated()).formLogin()// .successForwardUrl(/success) // 默认的话,跳转到你在认证之前的请求.// .defaultSuccessUrl(/success, true) // true,表示强制跳转到指定的url.successHandler(new AuthenticationSuccessHandler() { // security提供给我们的,认证成功之后的处理.我们可以在这里返回json给前端.// 前后端分离项目使用的方式;Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {// 给前端返回一个json串.应用于前后端分离的项目.MapString, Object map new HashMap();map.put(code, 0); // 状态码map.put(msg, 认证成功);map.put(authentication, authentication); ​PrintWriter writer response.getWriter();String json new ObjectMapper().writeValueAsString(map);writer.print(json);}}).and().csrf(csrf - csrf.disable()).build();} } ​ 认证流程: 浏览器输入了用户名称和密码 — 服务器 – security 进行认证, 怎么认证的? UsernamePasswordAuthenticaionFilter AbstractAuthenticationProcessingFilter 我们去认证的时候,服务器把密码存储到哪里地了. UserDetailsService UserDetailsManager, 用户信息管理.接口.封装了对用户所有操作. InMemoryUserDetailsManager, 基于内存实现的.也就是说,将用户信息都存储在内存当中了. 2.2 如何自定义认证 DaoAuthenticationProvider protected void additionalAuthenticationChecks(UserDetails userDetails,UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {if (authentication.getCredentials() null) {this.logger.debug(Failed to authenticate since no credentials provided);throw new BadCredentialsException(this.messages.getMessage(AbstractUserDetailsAuthenticationProvider.badCredentials, Bad credentials));}String presentedPassword authentication.getCredentials().toString();if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {this.logger.debug(Failed to authenticate since password does not match stored value);throw new BadCredentialsException(this.messages.getMessage(AbstractUserDetailsAuthenticationProvider.badCredentials, Bad credentials));} } 数据放到了内存当中,使用的是: InMemoryUserDetailsManager, 从内存读取数据,实际开发当中,数据源, 一般情况来自于数据库.也就是说, 我们存储用户名称和密码应该是存储在数据当中,咱们进行认证的时候,应该是从数据当中获取用户名称和密码.替换掉默认的: InMemoryUserDetailsManager. 通过查看,类关系图.发现有一个接口: UserDetailsService package org.springframework.security.core.userdetails; // 如果我们要自定义实现读取的数据源, 则必须实现这个接口,重写这个方法. public interface UserDetailsService {// 通过用户名称获取用户的详细信息.// 返回值是一个UserDetails接口.实际上返回的应该是一个对象.UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; } ​ ​ ​ package org.springframework.security.core.userdetails; ​ import java.io.Serializable; import java.util.Collection; ​ import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; ​ /*** Provides core user information.** p* Implementations are not used directly by Spring Security for security purposes. They* simply store user information which is later encapsulated into {link Authentication}* objects. This allows non-security related user information (such as email addresses,* telephone numbers etc) to be stored in a convenient location.* p* Concrete implementations must take particular care to ensure the non-null contract* detailed for each method is enforced. See* {link org.springframework.security.core.userdetails.User} for a reference* implementation (which you might like to extend or use in your code).** author Ben Alex* see UserDetailsService* see UserCache* 用户详细信息* 1. 用户名称* 2. 用户密码* 3. 用户的权限列表* 1. 角色信息* 2. 权限信息*/ public interface UserDetails extends Serializable { ​/*** Returns the authorities granted to the user. Cannot return codenull/code.* return the authorities, sorted by natural key (never codenull/code)* 权限列表*/Collection? extends GrantedAuthority getAuthorities(); ​/*** Returns the password used to authenticate the user.* return the password* 获取用户密码*/String getPassword(); ​/*** Returns the username used to authenticate the user. Cannot return* codenull/code.* return the username (never codenull/code)* 用户名称*/String getUsername(); ​/*** Indicates whether the users account has expired. An expired account cannot be* authenticated.* return codetrue/code if the users account is valid (ie non-expired),* codefalse/code if no longer valid (ie expired)* 账号状态是否是过期的.*/boolean isAccountNonExpired(); ​/*** Indicates whether the user is locked or unlocked. A locked user cannot be* authenticated.* return codetrue/code if the user is not locked, codefalse/code otherwise*/boolean isAccountNonLocked(); ​/*** Indicates whether the users credentials (password) has expired. Expired* credentials prevent authentication.* return codetrue/code if the users credentials are valid (ie non-expired),* codefalse/code if no longer valid (ie expired)*/boolean isCredentialsNonExpired(); ​/*** Indicates whether the user is enabled or disabled. A disabled user cannot be* authenticated.* return codetrue/code if the user is enabled, codefalse/code otherwise*/boolean isEnabled(); ​ } ​ User, spring security提供的一个类,这个类实现了UserDetails接口. // username,表示我们根据用户名称,从内存或者数据库查询出来的用户名称. // password, 从内存或者数据库当中查询出来的密码 // authorities, 从内存或者数据库当中查询出来该用户名称对应的权限列表. public User(String username, String password, Collection? extends GrantedAuthority authorities) {this(username, password, true, true, true, true, authorities); } 重要的接口和实现类: UserDetailsService, UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; // 根据前端传递过来的用户名称,去数据当中查询出用户名称对应的详细信息,封装成UserDetails对象即可; InMemoryUserDetailsManager,它是一个实现类,它表示从内存当中读取. 我们如果要换成从数据库当中读取用户信息,则必须实现UserDetailsService接口,重写方法.查询出来的数据,封里成UserDetatils对象. UserDetails, 表示定义用户的各种各样的信息. 用户名称 用户密码 用户权限列表 实现类: User, 在UserDetailsService方法, loadUserByUsername返回它即可; 如果, controller当中的login,直接调用Service层,此时需要我们自己处理,整个验证过程. 现在我们如果在userDetailsService实现类当中,进行相关的业务处理,将验证过程直接交给了security. 不用我们操心了. 2.3 纯纯自定义 根据流程来说, 要将从内存获取数据方式改更从数据库进行查询. 自己定义一个UserDetailsService实现类,完成一个逻辑: ①. 根据用户名称去数据库查询出这个用户名称对应的数据. ②. 将查询出来的数据封装成UserDetails对象. package com.tingyi.service.impl; ​ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.qf.entity.TbUser; import com.qf.mapper.ITbUserMapper; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; ​ import java.util.Collections; import java.util.List; ​ /*** author 听忆* 自定义读取过程,之前是从在内存当中,根据用户名称获取用户详情,现在我们从数据库当中进行获取.* mybatis plus 来读取一下.*/ Service public class UserDetailsServiceImpl implements UserDetailsService {private final ITbUserMapper tbUserMapper; ​public UserDetailsServiceImpl(ITbUserMapper tbUserMapper) {this.tbUserMapper tbUserMapper;} ​Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 根据用户名称去数据库当中查找.LambdaQueryWrapperTbUser queryWrapper new LambdaQueryWrapper();queryWrapper.eq(TbUser::getUsername, username);// 查询出结果,根据咱们自己就没有处理它.TbUser user tbUserMapper.selectOne(queryWrapper); // 通过这个对象,获取密码.还有权限列表.// 最终我们得把获取到的数据封装成UserDetails对象.交给spring security处理去.ListGrantedAuthority grantedAuthorityList Collections.emptyList(); // 权限列表.// 封装UserDetails对象.// User是UserDetails实现类.所以咱们可以直接返回这个实现类对象.return new User(username, user.getPassword(), grantedAuthorityList);} } ​ 手动完成认证 整个spring security一共15个过滤器. 其中有一个负责账号密码认证的过滤器: UsernamePasswordAuthenticationFilter. 需要一个认证管理器: AutenticationManager, 咱们是配置类,将它注入到IoC容器当中. Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {return authenticationConfiguration.getAuthenticationManager(); } 直接调用认证方法: Overridepublic Result login(String username, String password) {try {// 1. 将用户名称和密码封装成UsernamePasswordAuthenticationToken.UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken new UsernamePasswordAuthenticationToken(username, password); ​// 2. 调用AuthenticationManager提供认证方法.// Authentication authenticate(Authentication authentication) throws AuthenticationException;Authentication authenticate authenticationManager.authenticate(usernamePasswordAuthenticationToken); ​// 3. 存储认证结果.SecurityContextHolder.getContext().setAuthentication(authenticate);return Result.success(认证成功, authenticate);}catch (AuthenticationException e){return Result.error(认证失败, e.getMessage());}} 更改配置文件 得去执行我们自己的认证页面. Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {return http.authorizeRequests(authorize -authorize.mvcMatchers(/tom, /login).permitAll().anyRequest().authenticated())// .formLogin() // 仅仅表示我使用表单验证, 但是配置用的都是默认的..formLogin(form - form.loginPage(/login.html).permitAll().successHandler(new AuthenticationSuccessHandler() {Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {// 给前端返回一个json串.应用于前后端分离的项目.response.setContentType(application/json;charsetutf-8);MapString, Object map new HashMap();map.put(code, 0); // 状态码map.put(msg, 认证成功);map.put(authentication, authentication); ​PrintWriter writer response.getWriter();String json new ObjectMapper().writeValueAsString(map);writer.print(json);}}).failureHandler(new AuthenticationFailureHandler() {Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {// 给前端返回一个json串.应用于前后端分离的项目.response.setContentType(application/json;charsetutf-8);MapString, Object map new HashMap();map.put(code, -1); // 状态码map.put(msg, 认证失败);map.put(exception, exception); ​PrintWriter writer response.getWriter();String json new ObjectMapper().writeValueAsString(map);writer.print(json);}})) ​// .successForwardUrl(/success) // 默认的话,跳转到你在认证之前的请求.// .defaultSuccessUrl(/success, true) // true,表示强制跳转到指定的url.csrf(csrf - csrf.disable()).build(); } 2.4 jwt dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-api/artifactIdversion0.11.2/version /dependency dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-impl/artifactIdversion0.11.2/versionscoperuntime/scope /dependency dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt-jackson/artifactId !-- or jjwt-gson if Gson is preferred --version0.11.2/versionscoperuntime/scope /dependency ​ !--解决高版本JDK问题-- !--javax.xml.bind.DatatypeConverter错误-- dependencygroupIdjavax.xml.bind/groupIdartifactIdjaxb-api/artifactIdversion2.3.0/version /dependency dependencygroupIdcom.sun.xml.bind/groupIdartifactIdjaxb-impl/artifactIdversion2.3.0/version /dependency dependencygroupIdcom.sun.xml.bind/groupIdartifactIdjaxb-core/artifactIdversion2.3.0/version /dependency dependencygroupIdjavax.activation/groupIdartifactIdactivation/artifactIdversion1.1.1/version /dependency JSON Web Token (JWT)是一个开放标准(RFC 7519)它定义了一种紧凑的、自包含的方式用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任因为它是数字签名的。 安全, 以json方式传输, 可以被验证和信任.本质还是一个字符串.定义规则,咱们可控的. package com.tingyi.utils; ​ import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; ​ import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter; import java.security.Key; import java.util.Date; import java.util.UUID; ​ /*** jwt工具类.*/ public class JwtUtil {/*** jwt过期时间*/public static final Long EXP_TTL 60 * 60 * 1000L; ​/*** jwt使用的密钥*/public static final String JWT_KEY c3R1ZHkgaGFyZCBhbmQgbWFrZSBwcm9ncmVzcyBldmVyeSBkYXku; ​/*** 创建jwt字符串* param id id* param issuer 创建的作者* param subject 用户主体* param ttlMillis 过期时间, 毫秒值* return jwt字符串*/public static String createJWT(String id, String issuer, String subject, long ttlMillis) {SignatureAlgorithm signatureAlgorithm SignatureAlgorithm.HS256;long nowMillis System.currentTimeMillis();Date now new Date(nowMillis); ​byte[] apiKeySecretBytes DatatypeConverter.parseBase64Binary(JWT_KEY);Key signingKey new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); ​JwtBuilder builder Jwts.builder().setId(id).setIssuedAt(now).setSubject(subject).setIssuer(issuer).signWith(signingKey, signatureAlgorithm); ​if (ttlMillis 0) {long expMillis nowMillis ttlMillis;Date exp new Date(expMillis);builder.setExpiration(exp);}return builder.compact();} ​/*** 创建jwt字符串* param issuer 作者信息* param subject 用户主体信息* param ttlMillis 过期时间, 毫秒值* return jwt字符串*/public static String createJwt(String issuer, String subject, long ttlMillis){return createJWT(uuid(), issuer, subject, ttlMillis);} ​/*** 创建jwt字符串* param issuer 作者信息* param subject 用户主体信息* return jwt字符串*/public static String createJwt(String issuer, String subject){return createJwt(issuer, subject, EXP_TTL);} ​/*** 创建jwt字符串* param subject 用户主体* return jwt字符串*/public static String createJwt(String subject){return createJwt(laoren, subject, EXP_TTL);} ​/*** uuid* return String*/private static String uuid(){return UUID.randomUUID().toString().replaceAll(-, );} ​/*** 解析jwt* param jwt jwt字符串* return Claims*/public static Claims parseJWT(String jwt) {Claims claims Jwts.parserBuilder().setSigningKey(DatatypeConverter.parseBase64Binary(JWT_KEY)).build().parseClaimsJws(jwt).getBody(); ​return claims;} ​public static void main(String[] args) {// 生成一个jwt串.String jwt createJWT(1024, tom, jack, EXP_TTL);System.out.println(jwt);// 解析jwt串.Claims claims parseJWT(jwt);Object subject claims.get(subject);System.out.println(subject);System.out.println(claims);System.out.println(claims.getSubject());System.out.println(claims.getIssuedAt());System.out.println(claims.getExpiration());} } 2.5 官网认证流程 Form Login :: Spring Security 2.6 RBAC模型 RBACRole-Based Access Control基于角色的访问控制。通过用户关联角色角色关联权限来间接的为用户赋予权限。 4.1. 创建表结构 下面是标准的RBAC模型关系表: 用户表 -- 用户表 CREATE TABLE sys_user (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 编号,name varchar(50) NOT NULL COMMENT 用户名,nick_name varchar(150) DEFAULT NULL COMMENT 昵称,password varchar(100) DEFAULT NULL COMMENT 密码,create_time datetime DEFAULT NULL COMMENT 创建时间,PRIMARY KEY (id),UNIQUE KEY name (name) ) ENGINEInnoDB AUTO_INCREMENT34 DEFAULT CHARSETutf8 COMMENT用户管理; 角色表 -- 角色表 CREATE TABLE sys_role (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 编号,name varchar(100) DEFAULT NULL COMMENT 角色名称,create_time datetime DEFAULT NULL COMMENT 创建时间,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT9 DEFAULT CHARSETutf8 COMMENT角色管理; 用户角色表 -- 用户角色表 CREATE TABLE sys_user_role (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 编号,user_id bigint(20) DEFAULT NULL COMMENT 用户ID,role_id bigint(20) DEFAULT NULL COMMENT 角色ID,create_time datetime DEFAULT NULL COMMENT 创建时间,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT88 DEFAULT CHARSETutf8 COMMENT用户角色; 菜单表 -- 菜单表 CREATE TABLE sys_menu (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 编号,name varchar(50) DEFAULT NULL COMMENT 菜单名称,parent_id bigint(20) DEFAULT NULL COMMENT 父菜单ID一级菜单为0,url varchar(200) DEFAULT NULL COMMENT 菜单URL,类型1.普通页面如用户管理 /sys/user 2.嵌套完整外部页面以http(s)开头的链接 3.嵌套服务器页面使用iframe:前缀目标URL(如SQL监控 iframe:/druid/login.html, iframe:前缀会替换成服务器地址),perms varchar(500) DEFAULT NULL COMMENT 授权(多个用逗号分隔如sys:user:add,sys:user:edit),type int(11) DEFAULT NULL COMMENT 类型   0目录   1菜单   2按钮,icon varchar(50) DEFAULT NULL COMMENT 菜单图标,order_num int(11) DEFAULT NULL COMMENT 排序,create_time datetime DEFAULT NULL COMMENT 创建时间,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT57 DEFAULT CHARSETutf8 COMMENT菜单管理; 角色菜单表 -- 角色菜单表 CREATE TABLE sys_role_menu (id bigint(20) NOT NULL AUTO_INCREMENT COMMENT 编号,role_id bigint(20) DEFAULT NULL COMMENT 角色ID,menu_id bigint(20) DEFAULT NULL COMMENT 菜单ID,create_time datetime DEFAULT NULL COMMENT 创建时间,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT623 DEFAULT CHARSETutf8 COMMENT角色菜单; 2.7 如何实现权限流程 按照: 认证的过程,其中实现了接口: UserDetailsService接口,之后,我们在重写的方法当中. Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {LambdaQueryWrapperTbUser queryWrapper new LambdaQueryWrapper();queryWrapper.eq(TbUser::getUsername, username);TbUser user tbUserMapper.selectOne(queryWrapper); // 通过这个对象,获取密码.还有权限列表.// 最终我们得把获取到的数据封装成UserDetails对象.交给spring security处理去.// 这个集合当中,包含两个东西// 角色列表, 应该通过用户id去数据库当中,通过多表查询给它查询出来. ListRole// 权限列表, 通过用户id, 去数据库当中,通过多表查询,权限查出来. ListMenuListGrantedAuthority grantedAuthorityList Collections.emptyList(); // 权限列表.// 上一步完成之后,将封装好的ListGrantedAuthority交给spring security,它会在我们需要验证权限的时候,就会给你验证了.// 如何知道我需要进行权限验证,当类上或者方法上标记相关注解了.则表示我需要验证了.// 当前登录的用户,是否有某个角色.// 当前登录的用户, 是否拥有这个权限.return new User(username, user.getPassword(), grantedAuthorityList); } Secured注解, 是否拥有某个角色,某些角色. PreAuthorize, 是否拥有某些权限.
http://www.zqtcl.cn/news/383216/

相关文章:

  • 模板建站代理3免费做网站
  • 酒店官方网站的功能建设百度网盟推广案例
  • 屯昌网站建设wap网站搭建
  • 毕设做音乐网站重庆正云环境网页制作
  • 免费网站建站w深圳罗湖建网站
  • 创建一个网站一般步骤有哪些互动网站策划
  • 文化传媒 网站设计宿迁网站建设价格
  • 网站开发五人分工是网站推广的案例
  • 海外网站制作seo技术
  • 包头网站建设熊掌号免费行情100个软件
  • 江门网站制作维护电子商务网站运营与管理
  • 动画网页制作网站常用的网络推广方法有
  • 一个设计网站多少钱sku电商是什么意思
  • 做网站优化有前景吗emlog和wordpress
  • 30天网站建设实录 pdf货源网站程序
  • 做企业网站需要多久培训机构 网站建设
  • 商业网站初期建设资金预算哈尔滨视频制作公司
  • 网站建设教程网哪个好wordpress 侧边栏 固定
  • 对网站主要功能界面进行赏析软件开发和app开发的区别
  • 西安市高陵区建设局网站如何重新安装电脑上的wordpress
  • 合肥网站快速优化排名全球人口多少亿
  • 中山网站关键字优化使用动易模版制作网站
  • 深圳营销网站建设报价广西住房建设厅网站
  • 爱站网appwordpress图片500
  • 北京网站排名制作图片点击就能跳转网站怎么做的
  • dw网站建设的数据库网站建设托管pfthost
  • 牛商网做网站成品网站1688入口
  • 涿鹿县建设局网站网络营销的定义和特点
  • 网站建设朋友圈怎么写深圳宝安区松岗
  • 苏州网站的建设哪个网站上做自媒体最好