91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java如何實現Token登錄驗證

發布時間:2023-03-16 14:17:25 來源:億速云 閱讀:253 作者:iii 欄目:開發技術

這篇文章主要介紹“Java如何實現Token登錄驗證”,在日常操作中,相信很多人在Java如何實現Token登錄驗證問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java如何實現Token登錄驗證”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

    一、JWT是什么?

    在介紹JWT之前,我們先來回顧一下利用token進行用戶身份驗證的流程:

    1、客戶端使用用戶名和密碼請求登錄

    2、服務端收到請求,驗證用戶名和密碼

    3、驗證成功后,服務端會簽發一個token,再把這個token返回給客戶端

    4、客戶端收到token后可以把它存儲起來,比如放到cookie中

    5、客戶端每次向服務端請求資源時需要攜帶服務端簽發的token,可以在cookie或者header中攜帶

    6、服務端收到請求,然后去驗證客戶端請求里面帶著的token,如果驗證成功,就向客戶端返回請求數據

    這種基于token的認證方式相比傳統的session認證方式更節約服務器資源,并且對移動端和分布式更加友好。其優點如下

    支持跨域訪問:cookie是無法跨域的,而token由于沒有用到cookie(前提是將token放到請求頭中),所以跨域后不會存在信息丟失問題
    無狀態:token機制在服務端不需要存儲session信息,因為token自身包含了所有登錄用戶的信息,所以可以減輕服務端壓力
    更適用CDN:可以通過內容分發網絡請求服務端的所有資料
    更適用于移動端:當客戶端是非瀏覽器平臺時,cookie是不被支持的,此時采用token認證方式會簡單很多
    無需考慮CSRF:由于不再依賴cookie,所以采用token認證方式不會發生CSRF,所以也就無需考慮CSRF的防御

    而JWT就是上述流程當中token的一種具體實現方式,其全稱是JSON Web Token

    通俗地說,JWT的本質就是一個字符串,它是將用戶信息保存到一個Json字符串中,然后進行編碼后得到一個JWT token,并且這個JWT token帶有簽名信息,接收后可以校驗是否被篡改,所以可以用于在各方之間安全地將信息作為Json對象傳輸。JWT的認證流程如下:

    1、首先,前端通過Web表單將自己的用戶名和密碼發送到后端的接口,這個過程一般是一個POST請求。建議的方式是通過SSL加密的傳輸(HTTPS),從而避免敏感信息被嗅探

    2、后端核對用戶名和密碼成功后,將包含用戶信息的數據作為JWT的Payload,將其與JWT Header分別進行Base64編碼拼接后簽名,形成一個JWT Token,形成的JWT Token就是一個如同lll.zzz.xxx的字符串
    3、后端將JWT Token字符串作為登錄成功的結果返回給前端。前端可以將返回的結果保存在瀏覽器中,退出登錄時刪除保存的JWT Token即可

    4、前端在每次請求時將JWT Token放入HTTP請求頭中的Authorization屬性中(解決XSS和XSRF問題)

    5、后端檢查前端傳過來的JWT Token,驗證其有效性,比如檢查簽名是否正確、是否過期、token的接收方是否是自己等等

    6、驗證通過后,后端解析出JWT Token中包含的用戶信息,進行其他邏輯操作(一般是根據用戶信息得到權限等),返回結果

    Java如何實現Token登錄驗證

    最后:說白了,JWT:JSON Web Token,其實token就是一段字符串,由三部分組成:Header,Payload,Signature

    二、使用步驟

    1.項目結構

    Java如何實現Token登錄驗證

    2.相關依賴

        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.22</version>
            </dependency>
    
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>5.7.21</version>
            </dependency>
    
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.4.3.2</version>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.79</version>
            </dependency>
    
            <dependency>
                <groupId>commons-beanutils</groupId>
                <artifactId>commons-beanutils</artifactId>
                <version>1.9.4</version>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.22</version>
            </dependency>
    
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.11.0</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.poi</groupId>
                <artifactId>poi-ooxml</artifactId>
                <version>4.1.2</version>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.1</version>
                <scope>test</scope>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <version>2.3.8.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>com.auth0</groupId>
                <artifactId>java-jwt</artifactId>
                <version>3.18.3</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
            </dependency>
        </dependencies>

    3.數據庫

    這里進行測試,所以用戶類只有用戶名密碼,自行創建

    Java如何實現Token登錄驗證

    4.相關代碼

    1、annotation包
    PassToken:

    package com.geesun.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/28 10:26
     * @description:用來跳過驗證的 PassToken
     */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PassToken {
        boolean required() default true;
    }

    UserLoginToken:

    package com.geesun.annotation;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/28 10:26
     * @description:用于登錄后才能操作的token
     */
    /*RetentionPolicy.RUNTIME:這種類型的Annotations將被JVM保留,
    所以他們能在運行時被JVM或其他使用反射機制的代碼所讀取和使用。*/
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UserLoginToken {
        boolean required() default true;
    }

    2、common包
    CodeMsg:

    package com.geesun.common;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/28 10:26
     * @description:返回提示
     */
    public class CodeMsg {
        private int retCode;
        private String message;
        // 按照模塊定義CodeMsg
        // 通用異常
        public static CodeMsg SUCCESS = new CodeMsg(0,"success");
        public static CodeMsg SERVER_EXCEPTION = new CodeMsg(500100,"服務端異常");
        public static CodeMsg PARAMETER_ISNULL = new CodeMsg(500101,"輸入參數為空");
        // 業務異常
        public static CodeMsg USER_NOT_EXSIST = new CodeMsg(500102,"用戶不存在");
        public static CodeMsg ONLINE_USER_OVER = new CodeMsg(500103,"在線用戶數超出允許登錄的最大用戶限制。");
        public static CodeMsg SESSION_NOT_EXSIST =  new CodeMsg(500104,"不存在離線session數據");
        public static CodeMsg NOT_FIND_DATA = new CodeMsg(500105,"查找不到對應數據");
        public static CodeMsg USER_OR_PASS_ERROR = new CodeMsg(500102,"賬號或者密碼錯誤,請重試!");
    
    
        private CodeMsg(int retCode, String message) {
            this.retCode = retCode;
            this.message = message;
        }
    
        public int getRetCode() {
            return retCode;
        }
        public String getMessage() {
            return message;
        }
        public void setMessage(String message) {
            this.message = message;
        }
    }

    Result:

    package com.geesun.common;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/28 10:26
     * @description:返回統一結果集
     */
    public class Result<T> {
    
        private String message;
        private int retCode;
        private T data;
    
        private Result(T data) {
            this.retCode = 200;
            this.message = "成功";
            this.data = data;
        }
    
        private Result(CodeMsg cm) {
            if(cm == null){
                return;
            }
            this.retCode = cm.getRetCode();
            this.message = cm.getMessage();
        }
    
        /**
         * 成功時候的調用
         * @return
         */
        public static <T> Result<T> success(T data){
            return new Result<T>(data);
        }
    
        /**
         * 成功,不需要傳入參數
         * @return
         */
        @SuppressWarnings("unchecked")
        public static <T> Result<T> success(){
            return (Result<T>) success("");
        }
        /**
         * 失敗時候的調用
         * @return
         */
        public static <T> Result<T> error(CodeMsg cm){
            return new Result<T>(cm);
        }
        /**
         * 失敗時候的調用,擴展消息參數
         * @param cm
         * @param msg
         * @return
         */
        public static <T> Result<T> error(CodeMsg cm,String msg){
            cm.setMessage(cm.getMessage()+"--"+msg);
            return new Result<T>(cm);
        }
        public T getData() {
            return data;
        }
        public String getMessage() {
            return message;
        }
        public int getRetCode() {
            return retCode;
        }
    }

    3、config包
    InterceptorConfig:

    package com.geesun.config;
    
    import com.geesun.Interceptor.AuthenticationInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.format.FormatterRegistry;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.validation.MessageCodesResolver;
    import org.springframework.validation.Validator;
    import org.springframework.web.method.support.HandlerMethodArgumentResolver;
    import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
    import org.springframework.web.servlet.HandlerExceptionResolver;
    import org.springframework.web.servlet.config.annotation.*;
    import java.util.List;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/28 10:25
     * @description:新建Token攔截器
     */
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(authenticationInterceptor())
                    .addPathPatterns("/**");    // 攔截所有請求,通過判斷是否有 @LoginRequired 注解 決定是否需要登錄
        }
        @Bean
        public AuthenticationInterceptor authenticationInterceptor() {
            return new AuthenticationInterceptor();
        }
        @Override
        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void addCorsMappings(CorsRegistry arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void addFormatters(FormatterRegistry arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void addViewControllers(ViewControllerRegistry arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void configureAsyncSupport(AsyncSupportConfigurer arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void configureContentNegotiation(ContentNegotiationConfigurer arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void configurePathMatch(PathMatchConfigurer arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void configureViewResolvers(ViewResolverRegistry arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> arg0) {
            // TODO Auto-generated method stub
    
        }
        @Override
        public MessageCodesResolver getMessageCodesResolver() {
            // TODO Auto-generated method stub
            return null;
        }
        @Override
        public Validator getValidator() {
            // TODO Auto-generated method stub
            return null;
        }
    
    }

    4、Interceptor包
    AuthenticationInterceptor:

    package com.geesun.Interceptor;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.JWTVerifier;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.auth0.jwt.exceptions.JWTDecodeException;
    import com.auth0.jwt.exceptions.JWTVerificationException;
    import com.geesun.annotation.PassToken;
    import com.geesun.annotation.UserLoginToken;
    import com.geesun.pojo.User;
    import com.geesun.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.method.HandlerMethod;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.lang.reflect.Method;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/28 10:24
     * @description:攔截器
     */
    public class AuthenticationInterceptor implements HandlerInterceptor {
    
        @Autowired
        UserService userService;
    
        @Override
        public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
            String token = httpServletRequest.getHeader("token");// 從 http 請求頭中取出 token
            // 如果不是映射到方法直接通過
            if(!(object instanceof HandlerMethod)){
                return true;
            }
            HandlerMethod handlerMethod=(HandlerMethod)object;
            Method method=handlerMethod.getMethod();
            //檢查是否有passtoken注釋,有則跳過認證
            if (method.isAnnotationPresent(PassToken.class)) {
                PassToken passToken = method.getAnnotation(PassToken.class);
                if (passToken.required()) {
                    return true;
                }
            }
            //檢查有沒有需要用戶權限的注解
            if (method.isAnnotationPresent(UserLoginToken.class)) {
                UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
                if (userLoginToken.required()) {
                    // 執行認證
                    if (token == null) {
                        throw new RuntimeException("無token,請重新登錄");
                    }
                    // 獲取 token 中的 user id
                    String userId;
                    try {
                        userId = JWT.decode(token).getAudience().get(0);
                    } catch (JWTDecodeException j) {
                        throw new RuntimeException("401");
                    }
                    User user = userService.findUserById(userId);
                    if (user == null) {
                        throw new RuntimeException("用戶不存在,請重新登錄");
                    }
                    // 驗證 token
                    JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
                    try {
                        jwtVerifier.verify(token);
                    } catch (JWTVerificationException e) {
                        throw new RuntimeException("401");
                    }
                    return true;
                }
            }
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
    
        }
        @Override
        public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
    
        }
    }

    5、utils包
    TokenUtil:

    package com.geesun.utils;
    
    import com.auth0.jwt.JWT;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import javax.servlet.http.HttpServletRequest;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/28 10:24
     * @description:
     */
    public class TokenUtil {
    
        public static String getTokenUserId() {
            String token = getRequest().getHeader("token");// 從 http 請求頭中取出 token
            String userId = JWT.decode(token).getAudience().get(0);
            return userId;
        }
    
        /**
         * 獲取request
         * @return
         */
        public static HttpServletRequest getRequest() {
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes();
            return requestAttributes == null ? null : requestAttributes.getRequest();
        }
    
    }

    6、pojo包
    User:

    package com.geesun.pojo;
    
    import com.baomidou.mybatisplus.annotation.IdType;
    import com.baomidou.mybatisplus.annotation.TableField;
    import com.baomidou.mybatisplus.annotation.TableId;
    import com.baomidou.mybatisplus.annotation.TableName;
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.io.Serializable;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @TableName(value = "`user`")
    public class User implements Serializable {
        @TableId(value = "id", type = IdType.NONE)
        private String id;
    
        @TableField(value = "username")
        private String username;
    
        @TableField(value = "password")
        private String password;
    
        private static final long serialVersionUID = 1L;
    }

    7、controller包
    UserController:

    package com.geesun.controller;
    
    import cn.hutool.json.JSONObject;
    import com.geesun.annotation.UserLoginToken;
    import com.geesun.common.CodeMsg;
    import com.geesun.common.Result;
    import com.geesun.pojo.User;
    import com.geesun.service.UserService;
    import com.geesun.service.impl.TokenService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    import javax.servlet.http.Cookie;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/26 10:47
     * @description:
     */
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Autowired
        private UserService userService;
    
        @Autowired
        private TokenService tokenService;
    
        /**
         * 查詢用戶信息
         * @return
         */
        @UserLoginToken
        @GetMapping("/list")
        public Result<Object> list(){
            return Result.success(userService.list());
        }
    
    
        /**
         * 登錄驗證
         * @param user
         * @param response
         * @return
         */
        @RequestMapping(value = "/login" ,method = RequestMethod.GET)
        public Result<Object> login(User user, HttpServletResponse response) {
            JSONObject jsonObject = new JSONObject();
            //獲取用戶賬號密碼
            User userForBase = new User();
            userForBase.setId(userService.findByUsername(user).getId());
            userForBase.setUsername(userService.findByUsername(user).getUsername());
            userForBase.setPassword(userService.findByUsername(user).getPassword());
            //判斷賬號或密碼是否正確
            if (!userForBase.getPassword().equals(user.getPassword())) {
                return Result.error(CodeMsg.USER_OR_PASS_ERROR);
            } else {
                String token = tokenService.getToken(userForBase);
                jsonObject.put("token", token);
                Cookie cookie = new Cookie("token", token);
                cookie.setPath("/");
                response.addCookie(cookie);
                return Result.success(jsonObject);
            }
        }
        
    }

    8、service包
    UserService接口:

    package com.geesun.service;
    
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.geesun.pojo.User;
    
    public interface UserService extends IService<User> {
    
    
        int deleteByIds(Long[] ids);
    
        int addUser(User user);
    
        User findByUsername(User user);
    
        User findUserById(String userId);
    }

    UserServiceImpl實現類:

    package com.geesun.service.impl;
    
    import cn.hutool.core.util.ArrayUtil;
    import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.geesun.mapper.UserMapper;
    import com.geesun.pojo.User;
    import com.geesun.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.Arrays;
    
    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    
        @Autowired
        private UserMapper userMapper;
        
        /**
         * 判斷用戶名
         * @param user
         * @return
         */
        public User findByUsername(User user){
            return userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername,user.getUsername()));
        }
    
        public User findUserById(String userId) {
            return userMapper.selectById(userId);
        }
    
    }

    TokenService:

    package com.geesun.service.impl;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.algorithms.Algorithm;
    import com.geesun.pojo.User;
    import org.springframework.stereotype.Service;
    import java.util.Date;
    
    /**
     * @author :Mr.ZJW
     * @date :Created 2022/2/28 10:20
     * @description:
     */
    @Service
    public class TokenService {
    
        public String getToken(User user) {
            Date start = new Date();
            long currentTime = System.currentTimeMillis() + 60* 60 * 1000;//一小時有效時間
            Date end = new Date(currentTime);
            String token = "";
    
            token = JWT.create().withAudience(user.getId()).withIssuedAt(start).withExpiresAt(end)
                    .sign(Algorithm.HMAC256(user.getPassword()));
            return token;
        }
    }

    9、mapper包

    package com.geesun.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.geesun.pojo.User;
    
    public interface UserMapper extends BaseMapper<User> {
    
    }

    三、測試結果

    1、登錄驗證

    Java如何實現Token登錄驗證

    2、查詢用戶信息
    這個方法加上了@UserLoginToken,所以要token才能查詢

    Java如何實現Token登錄驗證

    Java如何實現Token登錄驗證

    3、不加上Token進行測試就會出錯提示

    Java如何實現Token登錄驗證

    出錯提示:

    Java如何實現Token登錄驗證

    到此,關于“Java如何實現Token登錄驗證”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    景洪市| 定州市| 赤城县| 淄博市| 松江区| 南江县| 东阿县| 鄯善县| 四会市| 论坛| 柳州市| 冀州市| 临泽县| 利津县| 博白县| 西青区| 新昌县| 阳山县| 裕民县| 巩留县| 阿鲁科尔沁旗| 吉安县| 赤壁市| 潮州市| 永德县| 水城县| 浮梁县| 白山市| 精河县| 衡东县| 汤原县| 吴忠市| 北海市| 翁牛特旗| 五峰| 揭阳市| 沙田区| 柳江县| 和硕县| 萝北县| 秦皇岛市|