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

西宁网站设计制作公司回龙观网站建设

西宁网站设计制作公司,回龙观网站建设,iot物联网平台开发,有什么好的手机推荐网站一、代码先行 1、设计模式 SpringSecurity 采用的是 责任链 的设计模式#xff0c;是一堆过滤器链的组合#xff0c;它有一条很长的过滤器链。 不过我们不需要去仔细了解每一个过滤器的含义和用法,只需要搞定以下几个问题即可#xff1a;怎么登录、怎么校验账户、认证失败…一、代码先行 1、设计模式 SpringSecurity 采用的是 责任链 的设计模式是一堆过滤器链的组合它有一条很长的过滤器链。 不过我们不需要去仔细了解每一个过滤器的含义和用法,只需要搞定以下几个问题即可怎么登录、怎么校验账户、认证失败处理。 2、 POM依赖 没啥好说的maven导入即可。 不写版本号默认就会下载 最新的 版本。 !--springSecurity-- dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId /dependency 3、登录 不管你用哪种权限框架第一个要解决的问题就是登录。就是在我们的登录接口中将账户密码委托给权限框架接管让权限框架帮我们做校验和权限认证。 新建一个登录方法目的是 验证用户的 用户名 和 密码并在验证成功后为该用户生成一个JWT。 GetMapping(/login) public String securityLogin(String username,String password){UsernamePasswordAuthenticationToken authToken new UsernamePasswordAuthenticationToken(username,password);// 使用authenticationManager调用loadUserByUsername获取数据库中的用户信息,Authentication authentication authenticationManager.authenticate(authToken);if(authentication null) {throw new RuntimeException(登录失败啦呀);}//获取符合security规范的UserSecurityUser securityUser (SecurityUser) authentication.getPrincipal();String token jwtUtil.createToken(securityUser.getUser());return token; }UsernamePasswordAuthenticationToken就是 我们委托 框架 帮我们托管 的 登录凭证。 然后是 单词重点说明 authenticate v 证明…是事实 authentication n证明 Authentication authentication authenticationManager.authenticate(authToken); 这就是spring security帮我们 执行 认证 和 授权 的方法最终返回一个 认证结果。 大家思考一下正常登录的逻辑无非是 4步走 输入账号密码根据账号从 DB数据库 中获取用户实体校验密码是否正确校验成功将用户生成token后返回 我们再回过来看 上面的代码第2步和第3步没见到。 肯定是spring security已经帮我们做了但是这并不代表我们可以省略这两步只是需要我们写在别的地方仅此而已。 4、根据账号从DB中获取用户实体 这个步骤是不可能不写的只是写到了别处。 说明一点spring security中的 用户概念有自己的一套规则不能直接用 我们系统里面的 User类。 因此如果我们要用spring security就得 实现 他的 用户接口UserDetails。 所以我们新建一个SecurityUser类 Data NoArgsConstructor public class SecurityUser implements UserDetails {// 使用聚合模式将我们自己的User对象聚合到SecurityUser中// user字段存储了用户的一些信息例如用户名和密码等private User user;// 覆盖UserDetails接口中的getAuthorities方法返回用户的权限集合// 这里返回null表示未实现获取权限的逻辑Overridepublic Collection? extends GrantedAuthority getAuthorities() {return null;}// 覆盖UserDetails接口中的getPassword方法返回用户的密码// 这里通过调用user对象的getPwd方法获取密码Overridepublic String getPassword() {return user.getPwd();}// 覆盖UserDetails接口中的getUsername方法返回用户的用户名// 这里通过调用user对象的getUserName方法获取用户名并注释说明有的地方可能会用email作为用户名这里还是使用userNameOverridepublic String getUsername() {// 用户名有的地方可能会用email作为用户名我们这还是userNamereturn user.getUserName();}// 覆盖UserDetails接口中的isAccountNonExpired方法判断账户是否过期// 这里直接返回true表示账户不过期Overridepublic boolean isAccountNonExpired() {return true;}// 覆盖UserDetails接口中的isAccountNonLocked方法判断账户是否被锁定// 这里直接返回true表示账户未被锁定Overridepublic boolean isAccountNonLocked() {return true;}// 覆盖UserDetails接口中的isCredentialsNonExpired方法判断凭证是否过期// 这里直接返回true表示凭证不过期Overridepublic boolean isCredentialsNonExpired() {return true;}// 覆盖UserDetails接口中的isEnabled方法判断用户是否启用// 这里直接返回true表示用户启用状态为trueOverridepublic boolean isEnabled() {return true;} } 虽然我们系统里面有自己的 user 了但是为了适配所以就 聚合 进来。 然后是如何查询DB肯定得有个 Service 去查询我们已经有自己的UserService了但是很可惜spring security 这个地方也有自己的规范我们自己写的user Service人家不认唉。 没办法重新写个Service自己写都写了也不能丢了所以 依照上面的操作还是聚合进来。 Service Slf4j public class UserDetailService implements UserDetailsService {ResourceUserService userService;/*** 根据用户名直接从DB中查询用户数据作为登录校验的依据* param username* return* throws UsernameNotFoundException*/Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user userService.getByUsername(username);if (user null) {log.info(username not found);throw new UsernameNotFoundException(username not found);}SecurityUser securityUser new SecurityUser();securityUser.setUser(user);return securityUser;} }核心逻辑 是我们还是用之前的方法拿到 User但为了适配就塞到 SecurityUser 里面去。 UserDetailsService 是spring security认可的接口我们得实现这个接口并且实现loadUserByUsername方法这个方法在spring security的认证逻辑里面会用到。目的就是拿到DB中真实的User跟我们登录的账号密码进行比对。 5、校验密码是否正确 很多时候我们的密码是要进行加密的但是我们登录肯定传的是明文密码所以需要转换后再去比对。 这个 校验密码 的逻辑需要写在spring security的 配置类 中。 Configuration EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {ResourceUserDetailService userService;/*** 新增security账户* param auth* throws Exception*/Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService).passwordEncoder(new PasswordEncoder() {Overridepublic String encode(CharSequence rawPassword) {return rawPassword.toString();}Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {return rawPassword.equals(encodedPassword);}});}}因为我们的项目并没有对密码加密所以就直接比较了。 在 LoginController 中我们用到了AuthenticationManager这个对象需要在配置类中注册。 Bean Override public AuthenticationManager authenticationManagerBean() throws Exception {// 身份验证管理器, 直接继承即可.return super.authenticationManagerBean(); } AuthenticationManager 是 Spring Security框架中的一个核心接口它负责处理身份验证请求。 在认证过程中用户提交身份验证信息如用户名和密码AuthenticationManager 会验证这些信息的有效性。 最后是 路由 的相关配置 Override protected void configure(HttpSecurity http) throws Exception { http // 禁用跨站请求伪造保护 .csrf().disable() // 设置会话管理策略为无会话因为我们使用token作为信息传递介质 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() // 进行认证请求的配置 .authorizeRequests() // 将所有登入和注册的接口放开这些都是无需认证就访问的 .antMatchers(/security/login).anonymous() // 除了上面的那些剩下的任何接口请求都需要经过认证 .anyRequest().authenticated() .and() // 允许跨域请求 .cors() ; // 在UsernamePasswordAuthenticationFilter之前添加JWT认证过滤器 http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); } 这段代码是Spring Security框架中用于配置HTTP安全的部分。它主要涉及到跨站请求伪造CSRF的禁用、会话管理策略的设置、认证请求的配置以及跨域请求的允许。同时还添加了一个JWTJSON Web Token认证过滤器。 因为我们项目用到了jwt所以在进行账号密码验证之前要先走jwt的过滤器。 jwt过滤器代码如下 Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {ResourceJWTUtil jwtUtil;Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException, ServletException, IOException {//获取tokenString token request.getHeader(token);if (!StringUtils.hasText(token)) {//token为空的话, 就不管它, 让SpringSecurity中的其他过滤器处理请求//请求放行filterChain.doFilter(request, response);return;}//token不为空时, 解析tokenUser user null;try {user jwtUtil.verify(token);} catch (Exception e) {// 过滤器中抛出的异常无法被统一异常捕获所以在这里直接返回e.printStackTrace();Result result new Result();result.setCode(403);result.setMsg(Token无效 e.getMessage());WebUtils.response(response,result);return;}SecurityUser securityUser new SecurityUser();securityUser.setUser(user);//将用户安全信息存入SecurityContextHolder, 在之后SpringSecurity的过滤器就不会拦截UsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(securityUser, null, null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);//放行filterChain.doFilter(request, response);} } 流程参考这个图 如果校验成功了那么在登录方法中就会往下走生成token返回结束。 6、全局异常返回 认证过程中难免出现各种异常我们一般会做一个通用的返回 Result Data public class Result implements Serializable {private int code;private String msg;private Object data;public static Result succ(Object data) {return success(200, 操作成功, data);}public static Result error(String msg) {return error(400, msg, null);}public static Result success (int code, String msg, Object data) {Result result new Result();result.setCode(code);result.setMsg(msg);result.setData(data);return result;}public static Result error (int code, String msg, Object data) {Result result new Result();result.setCode(code);result.setMsg(msg);result.setData(data);return result;} }GlobalExceptionHandler /*** 全局异常处理*/ Slf4j RestControllerAdvice public class GlobalExceptionHandler {/*** 400 错误运行时异常* param e* return*/ResponseStatus(HttpStatus.BAD_REQUEST)ExceptionHandler(value RuntimeException.class)public Result handler(RuntimeException e) {log.error(运行时异常----------------{}, e.getMessage());return Result.error(e.getMessage());}/*** 403 错误权限不足* param e* return*/ResponseStatus(HttpStatus.FORBIDDEN)ExceptionHandler(value AccessDeniedException.class)public Result handler(AccessDeniedException e) {log.info(security权限不足----------------{}, e.getMessage());return Result.error(权限不足);}/*** 400 错误异常请求-方法参数不匹配* param e* return*/ResponseStatus(HttpStatus.BAD_REQUEST)ExceptionHandler(value MethodArgumentNotValidException.class)public Result handler(MethodArgumentNotValidException e) {log.info(实体校验异常----------------{}, e.getMessage());BindingResult bindingResult e.getBindingResult();ObjectError objectError bindingResult.getAllErrors().stream().findFirst().get();return Result.error(objectError.getDefaultMessage());}/*** 400 错误异常请求-非法参数* param e* return*/ResponseStatus(HttpStatus.BAD_REQUEST)ExceptionHandler(value IllegalArgumentException.class)public Result handler(IllegalArgumentException e) {log.error(Assert异常----------------{}, e.getMessage());return Result.error(e.getMessage());}}二、原理亮明 Spring Security 它专注于身份验证和授权并可根据需求进行配置和自定义。在实际应用中了解身份验证组件的概念对于使用 Spring Security 进行实现和自定义非常有帮助。 1、没有使用 Spring Security 如果我们没有使用 Spring Security那么请求将被 DispatcherServlet 拦截。 DispatcherServlet 服务分发器 它拦截任何 HTTP 请求并将其转发到正确的控制器。 在 Spring Boot 中DispatcherServlet 会被自动配置。 2、DispatcherServlet 是如何工作的 在深入了解 Spring Security 之前让我们先了解一下 DispatcherServlet 如何分发请求。 当我们在一个端点比如 /hello/world发出请求时DispatcherServlet 会如何处理它 DispatcherServlet 创建了一个 IOC 容器它是 Spring Framework 的核心组件之一用于管理 bean 的创建和依赖关系。DispatcherServlet 创建的是 WebApplicationContext这是一个专门用于 Web 应用程序的 IOC 容器。WebApplicationContext 是根据配置文件由 DispatcherServlet 进行配置的。 该 IOC 容器 会创建控制器 bean 的实例。当请求到达时DispatcherServlet 会使用 IOC 容器 查找适当的 控制器 bean并 委托 给它来 处理请求。 3、使用 Spring Security 当将 Spring Security 添加到 Spring Boot 应用程序中时所有请求在到达 DispatcherServlet 之前 都会被 Spring Security 拦截。 4、认证 流程 身份验证请求和响应 虽然 Spring Security 可以与不同类型的身份验证方法一起使用但在本文中我们讨论的是 用户名和密码 方式的 身份验证以便深入了解完整的身份验证流程。 Filter Chain 在将请求转发给 Dispatcher Servlet 之前拦截传入请求。 请求进入认证过滤器其中一个过滤器是 UsernamePasswordAuthenticationFilter。 过滤器从请求HttpServletRequest 对象中提取用户名和密码。 然后使用凭据创建 UsernamePasswordAuthenticationToken。 调用 AuthenticationManager 的 authenticate() 方法。 AuthenticationManager 的 authenticate() 方法实现将尝试使用其拥有的 AuthenticationProvider 之一进行身份验证。 如果一个身份验证提供程序能够成功进行身份验证它将返回一个包含凭据和权限的完整的 UsernamePasswordAuthenticationToken。 提供程序返回的此令牌用于在 Spring Security 上下文中将用户设置为已认证。 一旦用户通过身份验证请求就会被转发到处理请求的 DispatcherServlet。 5、认证流程 中涉及到的 组件 5.1 什么是过滤器 Spring Filter 是一个组件可以拦截任何传入请求并在将其传递给 DispatcherServlet 之前执行某些操作。 过滤器可以处理请求然后将其转发到 Filter Chain 中的下一个过滤器或者可以停止并发送回 HTTP 响应。其中一个过滤器是存在于 FilterChain 中的 UsernamePasswordAuthenticationFilter。此过滤器尝试查找 HTTP Post 请求中传递的用户名和密码如果找到则尝试使用凭据对用户进行身份验证。 我们可以创建自己的 Filter 并将其添加到 SecurityFilterChain 中以提供自己的逻辑来处理请求。 5.2 什么是 AuthenticationManager AuthenticationManager 是一个接口用于处理 身份验证 的过程。它只有一个方法 authenticate(Authentication authentication)该方法将一个身份验证对象作为参数并返回 已经认证的 身份验证对象。身份验证对象通常是一个包含用户名和密码等凭据的 AuthenticationToken 对象。 Authentication authenticate(Authentication authentication) throws AuthenticationException; AuthenticationManager 的 实现类 是 ProviderManager 类它提供了 authenticate() 方法的逻辑。 我们可以提供我们自己的 AuthenticationProvider 实现类 或 使用默认实现。 5.3 什么是 ProviderManager 该类 实现 了 AuthenticationManager 接口 并覆盖了 authenticate() 方法。 它使用一组 AuthenticationProvider 来验证 Authentication 对象中发送的凭据。如果 AuthenticationProvider 支持身份验证类型则将用于验证用户。如果没有提供者支持身份验证类型则将抛 AuthenticationException。 每个身份验证提供程序的 supports() 方法用于检查它是否可以支持所需的身份验证类型。 5.4 什么是 AuthenticationProvider AuthenticationProvider 是一个接口用于定义验证用户的协议。它负责接收 Authentication 对象表示用户凭据并返回已经认证的 Authentication 对象如果凭据有效。如果凭据无效则 AuthenticationProvider 应该抛出 AuthenticationException。 AuthenticationProvider 接口有两个方法 authenticate()此方法接受 Authentication 对象作为输入并在凭据有效时返回已认证的 Authentication 对象。如果凭据无效则 AuthenticationProvider 应该抛出 AuthenticationException。 supports()此方法接受 Authentication 对象作为输入并且如果 AuthenticationProvider 可以验证该对象则返回 true。如果 AuthenticationProvider 无法验证该对象则应返回 false。 Spring Security 中的默认 AuthenticationProvider 是 DaoAuthenticationProvider。此提供程序使用 UserDetailsService 从数据库加载用户详细信息。如果用户凭据与数据库中的详细信息匹配则 DaoAuthenticationProvider 将返回已经认证的 Authentication 对象。 我们可以添加我们自己的 AuthenticationProvider 实现来提供不同的身份验证方法。 5.5 身份验证和 UsernamePasswordAuthenticationToken Authentication 和 UsernamePasswordAuthenticationToken 是什么 Authentication 这是 Spring Security 中的一个接口表示传入身份验证请求的令牌或已认证的主体表示一个实体比如个人AuthenticationManager.authenticate() 方法。 提供的一些方法为 Collection? extends GrantedAuthority getAuthorities();Object getCredentials();boolean isAuthenticated();void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException; UsernamePasswordAuthenticationToken 此类扩展了 AbstractAuthenticationToken 类身份验证对象的基类可用于用户名/密码身份验证请求。 此类有两个构造函数 public UsernamePasswordAuthenticationToken(Object principal, Object credentials) {super((Collection)null);this.principal principal;this.credentials credentials;this.setAuthenticated(false); }public UsernamePasswordAuthenticationToken(Object principal, Object credentials, Collection? extends GrantedAuthority authorities) {super(authorities);this.principal principal;this.credentials credentials;super.setAuthenticated(true); }第一个构造函数可用于传入请求以创建未经身份验证的 Authentication 对象。 Authentication authentication new UsernamePasswordAuthenticationToken(username,password); 第二个构造函数可用于创建完全经过身份验证的 Authentication 对象。 Authentication authToken new UsernamePasswordAuthenticationToken(username, password, userAuthorities); 然后此完全经过身份验证的 Authentication 对象从 AuthenticationProvider/AuthenticationManager 返回并表示已认证的用户。然后将此已认证的对象设置在 SecurityContext 中。Spring Security 中的 SecurityContext 是当前执行线程的安全上下文的表示。它包含有关当前已认证用户的信息例如其用户名、权限和会话信息。
文章转载自:
http://www.morning.wfpmt.cn.gov.cn.wfpmt.cn
http://www.morning.cffwm.cn.gov.cn.cffwm.cn
http://www.morning.qzzmc.cn.gov.cn.qzzmc.cn
http://www.morning.mtrrf.cn.gov.cn.mtrrf.cn
http://www.morning.sthp.cn.gov.cn.sthp.cn
http://www.morning.nzkc.cn.gov.cn.nzkc.cn
http://www.morning.ubpsa.cn.gov.cn.ubpsa.cn
http://www.morning.egmux.cn.gov.cn.egmux.cn
http://www.morning.ljbch.cn.gov.cn.ljbch.cn
http://www.morning.gpsrk.cn.gov.cn.gpsrk.cn
http://www.morning.kxwsn.cn.gov.cn.kxwsn.cn
http://www.morning.zzfjh.cn.gov.cn.zzfjh.cn
http://www.morning.lhhdy.cn.gov.cn.lhhdy.cn
http://www.morning.zrdhd.cn.gov.cn.zrdhd.cn
http://www.morning.sxwfx.cn.gov.cn.sxwfx.cn
http://www.morning.xrpwk.cn.gov.cn.xrpwk.cn
http://www.morning.cywf.cn.gov.cn.cywf.cn
http://www.morning.hhnhb.cn.gov.cn.hhnhb.cn
http://www.morning.rrqgf.cn.gov.cn.rrqgf.cn
http://www.morning.rmpkn.cn.gov.cn.rmpkn.cn
http://www.morning.trfrl.cn.gov.cn.trfrl.cn
http://www.morning.wlgpz.cn.gov.cn.wlgpz.cn
http://www.morning.yfmwg.cn.gov.cn.yfmwg.cn
http://www.morning.cyjjp.cn.gov.cn.cyjjp.cn
http://www.morning.zlrrj.cn.gov.cn.zlrrj.cn
http://www.morning.dzgmj.cn.gov.cn.dzgmj.cn
http://www.morning.gxeqedd.cn.gov.cn.gxeqedd.cn
http://www.morning.wrlff.cn.gov.cn.wrlff.cn
http://www.morning.yjprj.cn.gov.cn.yjprj.cn
http://www.morning.qkqpy.cn.gov.cn.qkqpy.cn
http://www.morning.5-73.com.gov.cn.5-73.com
http://www.morning.mqss.cn.gov.cn.mqss.cn
http://www.morning.ytmx.cn.gov.cn.ytmx.cn
http://www.morning.qhjkz.cn.gov.cn.qhjkz.cn
http://www.morning.kqyyq.cn.gov.cn.kqyyq.cn
http://www.morning.zqbrw.cn.gov.cn.zqbrw.cn
http://www.morning.ccsdx.cn.gov.cn.ccsdx.cn
http://www.morning.qwpyf.cn.gov.cn.qwpyf.cn
http://www.morning.rynqh.cn.gov.cn.rynqh.cn
http://www.morning.xqxrm.cn.gov.cn.xqxrm.cn
http://www.morning.dfltx.cn.gov.cn.dfltx.cn
http://www.morning.pwmm.cn.gov.cn.pwmm.cn
http://www.morning.czrcf.cn.gov.cn.czrcf.cn
http://www.morning.kwfnt.cn.gov.cn.kwfnt.cn
http://www.morning.prznc.cn.gov.cn.prznc.cn
http://www.morning.jlpdc.cn.gov.cn.jlpdc.cn
http://www.morning.rmxwm.cn.gov.cn.rmxwm.cn
http://www.morning.mqldj.cn.gov.cn.mqldj.cn
http://www.morning.nmkfy.cn.gov.cn.nmkfy.cn
http://www.morning.rmdwp.cn.gov.cn.rmdwp.cn
http://www.morning.fmswb.cn.gov.cn.fmswb.cn
http://www.morning.fbqr.cn.gov.cn.fbqr.cn
http://www.morning.tlfzp.cn.gov.cn.tlfzp.cn
http://www.morning.rdbj.cn.gov.cn.rdbj.cn
http://www.morning.sloxdub.cn.gov.cn.sloxdub.cn
http://www.morning.reababy.com.gov.cn.reababy.com
http://www.morning.kbbmj.cn.gov.cn.kbbmj.cn
http://www.morning.qcdhg.cn.gov.cn.qcdhg.cn
http://www.morning.qmtzq.cn.gov.cn.qmtzq.cn
http://www.morning.gfqj.cn.gov.cn.gfqj.cn
http://www.morning.sbpt.cn.gov.cn.sbpt.cn
http://www.morning.cxryx.cn.gov.cn.cxryx.cn
http://www.morning.jzdfc.cn.gov.cn.jzdfc.cn
http://www.morning.ljtwp.cn.gov.cn.ljtwp.cn
http://www.morning.sbpt.cn.gov.cn.sbpt.cn
http://www.morning.nmkbl.cn.gov.cn.nmkbl.cn
http://www.morning.hbfqm.cn.gov.cn.hbfqm.cn
http://www.morning.mytmx.cn.gov.cn.mytmx.cn
http://www.morning.monstercide.com.gov.cn.monstercide.com
http://www.morning.bmzxp.cn.gov.cn.bmzxp.cn
http://www.morning.sgnxl.cn.gov.cn.sgnxl.cn
http://www.morning.nflpk.cn.gov.cn.nflpk.cn
http://www.morning.fprll.cn.gov.cn.fprll.cn
http://www.morning.qysnd.cn.gov.cn.qysnd.cn
http://www.morning.kntbk.cn.gov.cn.kntbk.cn
http://www.morning.npfrj.cn.gov.cn.npfrj.cn
http://www.morning.cnqdn.cn.gov.cn.cnqdn.cn
http://www.morning.kljhr.cn.gov.cn.kljhr.cn
http://www.morning.gglhj.cn.gov.cn.gglhj.cn
http://www.morning.dpdns.cn.gov.cn.dpdns.cn
http://www.tj-hxxt.cn/news/248245.html

相关文章:

  • 长春广告公司网站建设网站规划与网页设计案例
  • 国内信息图制作网站有哪些网站怎么优化排名的方法
  • 3000ok新开传奇网站公益服深圳市营销策划有限公司
  • 石家庄百度提升优化上海百度seo公司
  • 网站定制开发优点ckeditor导入wordpress
  • 数据查询网站如何做雅茂道网站建设
  • 网站正在备案中网站域名跳转代码
  • 做设计的兼职网站有哪些建设工程教育网题库
  • 怎么做传奇网站图做的网站电脑上跟手机上不一样吗
  • 怎样做网站导航栏最新网络游戏排行榜2021前十名
  • 投资建设网站网站建设属于什么岗位
  • 如何个网站做优化qq代挂网站建设
  • 销售网站建设方案百度收录推广
  • 高端网站设计公司wordpress 时区问题
  • 福永三合一网站设计wordpress如何发布文件
  • 做创意礼品定制的网站做一个网页难不难
  • 企业网站优化做法权重网站建设
  • 怎么查网站是哪个建站公司做的德州市建设工程质监站网站
  • 网站设计一般包括什么合肥网站建设培训
  • 电商网站怎么做权限控制网络营销推广有效方式
  • 做网络主播网站违法吗软件是怎么制作的
  • 旅游网站规划设计建设网站的费用明细大概有哪些
  • 泉州品牌网站设计定制有域名有空间怎么做网站
  • 和京东一样的网站桂林网站建设哪家好
  • 四川监理协会建设网站英文外贸网站模板
  • 如果让你建设一个网站云空间提供网站
  • 设计衣服的网站昆山市建设局网站6
  • 企业网站百度收录网站架构是什么
  • 网站可以更换域名吗房产网名字叫啥好听
  • 关于宠物的网站模板建筑工程有限责任公司