SpringMVC+JWT+Swagger UI+RestFul

前言:html

其實很早就想寫這篇文章了,由於我以爲這會對不少新手有指引做用,當初本身也是瞎子過河的摸索着過來的。目先後臺開發比較流行的MVC框架中使用Spring MVC仍是比較多的,固然還有Spring Boot,Spring Boot是基於 Spring4 的條件註冊的一套快速開發整合包,說白了就是簡化開發流程。你們能夠嘗試一下,可是這裏仍是以Spring MVC爲例子。前端

之因此使用jwt(json web token),是由於作後臺不一樣於作web,app由於是長時間的登陸至少都是一兩個月不操做任然處於登陸狀態,因此目前國內大可能是都是使用token作鑑權而不是使用session。而jwt是一個不錯的token技術。restful就不用多說了,如今比較流行的編程風格,多個客戶端(安卓,ios, mobile,web)調用同一套後臺接口,而這就使得這套後臺接口儘可能不附帶太多業務邏輯,而是面向資源的風格。而swaggerui則是提供一個rest api的可視化接口文檔,而且在開發完後,能夠很輕鬆的測試。java

固然你能夠只整合jwt或者swaggerui,教程都是沒問題的。ios

全部使用到的代碼能夠在這裏查看:https://github.com/minchangchen/springmvc-jwt-swaggerui

1.Spring MVCgit

Spring MVC框架是有一個MVC框架,經過實現Model-View-Controller模式來很好地將數據、業務與展示進行分離。從這樣一個角度來講,Spring MVC和Struts、Struts2很是相似。Spring MVC的設計是圍繞DispatcherServlet展開的,DispatcherServlet負責將請求派發到特定的handler。經過可配置的handler mappings、view resolution、locale以及theme resolution來處理請求而且轉到對應的視圖。這裏就不作太多介紹,開始想在維基百科上搜索下spring mvc的,結果發現並無這個條目,百度是有的。因此說有時候盈利的並非都很差。github

2.JWT(Json Web Tokens)web

定義:JWT是一種用於雙方之間傳遞安全信息的簡潔的、URL安全的表述性聲明規範。JWT做爲一個開放的標準( RFC 7519 ),定義了一種簡潔的,自包含的方法用於通訊雙方之間以Json對象的形式安全的傳遞信息。由於數字簽名的存在,這些信息是可信的,JWT可使用HMAC算法或者是RSA的公私祕鑰對進行簽名。算法

說明:傳統的鑑權機制是基於session-cookies,而隨着認證用戶的增多,服務端的開銷會明顯增大,且不適合作app應用驗證。由於app是一次登陸,退出後不需登陸,因此如今主流的鑑權驗證都是使用token驗證。而jwt是一種不錯的基於token的鑑權機制。spring

基本流程:docker

用戶使用用戶名密碼來請求服務器

服務器進行驗證用戶的信息

服務器經過驗證發送給用戶一個token

客戶端存儲token,並在每次請求時附送上這個token值

服務端驗證token值,並返回數據

推文:http://www.jianshu.com/p/576dbf44b2ae

3.RestFul

定義:網絡應用程序,分爲前端和後端兩個部分。當前的發展趨勢,就是前端設備層出不窮(手機、平板、桌面電腦、其餘專用設備......)。所以,必須有一種統一的機制,方便不一樣的前端設備與後端進行通訊。這致使API構架的流行,甚至出現"API First"的設計思想。RESTful API是目前比較成熟的一套互聯網應用程序的API設計理論。

說明:restful風格,就是一種面向資源服務的API設計方式,它不是規範,不是標準,它一種設計模式。之前流行的web service服務都是面向過程,基於RPC協議的SOAP協議,對於如今或者將來,更多的人瞭解而且深受SOA思想影響,以面向服務爲目標,而如今的SOAP雖然支持SOA,但存在很很大的差異,因此,慢慢就流行基於restful風格的web service。說簡單一點,就是它純粹面向資源,面向服務的思想,目前J2EE6的JAX-RS就是這種restful風格實現的新技術。

例子:

獲取用戶列表 GET:http://project.company.com/api/v1/users
獲取單個用戶 GET:http://project.company.com/api/v1/users/{uid:.{32}}
建立單個用戶 POST:http://project.company.com/api/v1/users/{uid:.{32}}
徹底替換用戶 PUT:http://project.company.com/api/v1/users/{uid:.{32}}
局部更新用戶 PATCH:http://project.company.com/api/v1/users/{uid:.{32}}
刪除單個用戶 DELETE:http://project.company.com/api/v1/users/{uid:.{32}}

推文: http://www.ruanyifeng.com/blog/2014/05/restful_api.html

4.Swagger UI

定義:Swagger的目標是爲REST APIs 定義一個標準的,與語言無關的接口,令人和計算機在看不到源碼或者看不到文檔或者不能經過網絡流量檢測的狀況下能發現和理解各類服務的功能。當服務經過Swagger定義,消費者就能與遠程的服務互動經過少許的實現邏輯。相似於低級編程接口,Swagger去掉了調用服務時的不少猜想。

說明:swagger ui用於管理項目中API接口,屬當前最流行的API接口管理工具。是後端開發人員提供給app開發人員的一個查看、測試、的一個可視化,可操做的接口文檔,在這裏你能夠知道須要給都太傳入什麼參數,使用哪一種請求,以及返回的數據等等,這種就省去app端人員寫測試接口。

圖示:

代碼:

1.maven

<!-- Spring -->
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>4.3.4.RELEASE</version>
	<exclusions>
		<!-- Exclude Commons Logging in favor of SLF4j -->
		<exclusion>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context-support</artifactId>
	<version>4.3.4.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>4.3.4.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-test</artifactId>
	<version>4.3.4.RELEASE</version>
</dependency>

<!-- springfox-swagger2 -->
<dependency>  
	 <groupId>io.springfox</groupId>  
	 <artifactId>springfox-swagger2</artifactId>  
	 <version>2.5.0</version>
</dependency>  
 <dependency>  
	 <groupId>io.springfox</groupId>  
	 <artifactId>springfox-swagger-ui</artifactId>  
	 <version>2.5.0</version>  
 </dependency>

 <!-- Jwt -->
<dependency>
	<groupId>io.jsonwebtoken</groupId>
	<artifactId>jjwt</artifactId>
	<version>0.7.0</version>
</dependency>

2.JWT

這裏我再也不解釋下jwt了,looking this :http://www.jianshu.com/p/576dbf44b2ae 必定要看哦!

我先說下jwt使用流程:

a:用戶登陸server

b:server驗證經過,生成token並返回

c:app端接收到token存起來,下去請求放在reuqest的header裏面

d:server接收到app的請求,在攔截器中判斷url是否爲須要鑑權的路徑,而後去驗證token

e:當token過時時,且沒有超過刷新期。自動添加一個新的token返回給app

攔截器:

public abstract class BaseWebInterceptor extends HandlerInterceptorAdapter {

	public static final String RedirectPrefix = "redirect:";
	private static Logger log = LoggerFactory.getLogger(BaseWebInterceptor.class);

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		if (isNeedJwtUrl(request.getRequestURI())) {	//判斷這個url是否須要jwt驗證 ,好比login就不須要
			String token = request.getHeader("x-access-token");		//從request中獲取token,key是自定義的,固然app端存也要是這個key
			ETokenState state = JwtUtil.validateJWT(token);			//驗證token,ETokenState這是我自定義的一個類,JwtUtil這也是本身寫的一個類
			switch (state) {		
			case invalid:		//驗證錯誤
				log.info(String.format("URL:%s need login, but the token is null or invalid... ", request.getRequestURL().toString()));
				response.setStatus(401);
				return false;
			case expired:		//token過時
				if (refreshTokenHandler(request, response, token)) {
					break;
				} else {
					log.info(String.format("URL:%s need login, but the token is expired... ", request.getRequestURL().toString()));
					response.setStatus(403);
					return false;
				}
			case valid:		//有效的
				break;
			default:
				break;
			}
		}
		return super.preHandle(request, response, handler);
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
		super.afterCompletion(request, response, handler, ex);
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
		super.postHandle(request, response, handler, modelAndView);
	}


	/**
	 * 刷新token,子類重載
	 * 
	 * @author chenmc
	 * @date 2017年5月9日 下午3:41:05
	 * @param token
	 * @return
	 */
	protected boolean refreshTokenHandler(HttpServletRequest request, HttpServletResponse response, String token) {
		return false;
	}


	/**
	 * 須要登陸的uri
	 * 
	 * @param requestURI
	 * @return
	 */
	private boolean isNeedJwtUrl(String requestURI) {
		return MappingConf.isNeedJwtUrls(requestURI);
	}

}

這裏須要說明的是,通常的login和register的url是不攔截的,本身能夠配置。關於jwt生成和驗證的代碼,請點擊這裏https://github.com/minchangchen/springmvc-jwt-swaggerui

2.Swagger UI

配置文件:

1,springmvc.xml

<!-- swagger2 -->
	<context:component-scan base-package="com.gionee.swagger.conf"/>
	<bean class="com.company.swagger.conf.SwaggerConfig"/>
	<!-- Swagger資源重定向(僅做爲後臺使用不提供靜態資源) -->
    <mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/>
    <mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>

2,SwaggerConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

//@Configuration
@EnableSwagger2
@EnableWebMvc
@ComponentScan("com.company.web")
public class SwaggerConfig {

    @Bean
    public Docket api(){
    	ParameterBuilder tokenPar = new ParameterBuilder();
    	List<Parameter> pars = new ArrayList<Parameter>();
		//增長一個request的header參數
    	tokenPar.name("x-access-token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
    	pars.add(tokenPar.build());
        return new Docket(DocumentationType.SWAGGER_2)
            .select()
            .apis(RequestHandlerSelectors.any())
            .paths(PathSelectors.regex("/api/.*"))//對全部請求中包含api的url攔截
            .build()
            .globalOperationParameters(pars)
            .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
            .title("後臺接口文檔與測試")
            .description("這是一個給app端人員調用server端接口的測試文檔與平臺")
            .version("1.0.0")
            .termsOfServiceUrl("http://terms-of-services.url")
            //.license("LICENSE")
            //.licenseUrl("http://url-to-license.com")
            .build();
    }

}

3,Controller

@Api(value="登陸接口")
@Controller
@RequestMapping("/api/v1")
public class LoginInterface extends BaseController {

	@Autowired
	UserSO so;
	
	@ApiOperation(value="驗證密文,並添加user", notes="密文和amigoInfo")
	@RequestMapping( value = {"/login"}, method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
	@ResponseBody
	public String login(HttpServletRequest request, @RequestParam String fields, @PathVariable String useruid) {
		// do something
	}
	
	/*
	*api開頭的註解都是swagger的註解
	*方法參數上加有@RequestParam的參數會顯示在swagger
	*因此上述login方法的三個參數只有fields會顯示在swagger中
	*固然還有一個請求頭的參數,存放token的那是在SaggerConfig.java中配置的
	*/
}

4,放開swagger的url不攔截

當你配置了jwt,由於jwt對url進行攔截,這裏咱們不能對swagger的URL進行攔截,這樣頁面才能正常顯示。只整合swaggerui的能夠忽略。

noNeedJwtUrls=.*swagger.*|.*docs.*|.*test.*|.*/index.*|.*/register.*|.*/login.*

至此,swaggerui已配置完成,請求訪問http://localhost:8080/proj-name/swagger-ui.html便可獲得如下頁面



3.RestFul API

請參照如下這種方式來定義接口

獲取用戶列表 GET:http://proj.company.com/api/v1/users

獲取單個用戶 GET:http://proj.company.com/api/v1/users/{uid:.{32}}

建立單個用戶  POST:http://proj.company.com/api/v1/users/{uid:.{32}}

徹底替換用戶 PUT:http://proj.company.com/api/v1/users/{uid:.{32}}

局部更新用戶 PATCH:http://proj.company.com/api/v1/users/{uid:.{32}}

刪除單個用戶 DELETE:http://proj.company.com/api/v1/users/{uid:.{32}}


至此,全部配置應該都已經貼出,代碼可在這裏查找:https://github.com/minchangchen/springmvc-jwt-swaggerui


如有遺失或錯誤但願你們提出!過段時間我會寫一些與docker有關的教程,這段時間以爲本身對docker的使用還不夠全及精,因此暫時不寫!

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息