javascript
SpringMVC+JWT+Swagger UI+RestFul
前言:
其實(shí)很早就想寫這篇文章了,因?yàn)槲矣X得這會(huì)對(duì)很多新手有指引作用,當(dāng)初自己也是瞎子過河的摸索著過來的。目前后臺(tái)開發(fā)比較流行的MVC框架中使用Spring MVC還是比較多的,當(dāng)然還有Spring Boot,Spring Boot是基于 Spring4 的條件注冊(cè)的一套快速開發(fā)整合包,說白了就是簡化開發(fā)流程。大家可以嘗試一下,但是這里還是以Spring MVC為例子。
之所以使用jwt(json web token),是因?yàn)樽龊笈_(tái)不同于做web,app因?yàn)槭情L時(shí)間的登錄至少都是一兩個(gè)月不操作任然處于登錄狀態(tài),所以目前國內(nèi)大多是都是使用token做鑒權(quán)而不是使用session。而jwt是一個(gè)不錯(cuò)的token技術(shù)。restful就不用多說了,現(xiàn)在比較流行的編程風(fēng)格,多個(gè)客戶端(安卓,ios, mobile,web)調(diào)用同一套后臺(tái)接口,而這就使得這套后臺(tái)接口盡量不附帶太多業(yè)務(wù)邏輯,而是面向資源的風(fēng)格。而swaggerui則是提供一個(gè)rest api的可視化接口文檔,并且在開發(fā)完后,可以很輕松的測(cè)試。
當(dāng)然你可以只整合jwt或者swaggerui,教程都是沒問題的。
所有使用到的代碼可以在這里查看:https://github.com/minchangchen/springmvc-jwt-swaggerui
1.Spring MVC
Spring MVC框架是有一個(gè)MVC框架,通過實(shí)現(xiàn)Model-View-Controller模式來很好地將數(shù)據(jù)、業(yè)務(wù)與展現(xiàn)進(jìn)行分離。從這樣一個(gè)角度來說,Spring MVC和Struts、Struts2非常類似。Spring MVC的設(shè)計(jì)是圍繞DispatcherServlet展開的,DispatcherServlet負(fù)責(zé)將請(qǐng)求派發(fā)到特定的handler。通過可配置的handler mappings、view resolution、locale以及theme resolution來處理請(qǐng)求并且轉(zhuǎn)到對(duì)應(yīng)的視圖。這里就不做太多介紹,開始想在維基百科上搜索下spring mvc的,結(jié)果發(fā)現(xiàn)并沒有這個(gè)條目,百度是有的。所以說有時(shí)候盈利的并不是都不好。
2.JWT(Json Web Tokens)
定義:JWT是一種用于雙方之間傳遞安全信息的簡潔的、URL安全的表述性聲明規(guī)范。JWT作為一個(gè)開放的標(biāo)準(zhǔn)( RFC 7519 ),定義了一種簡潔的,自包含的方法用于通信雙方之間以Json對(duì)象的形式安全的傳遞信息。因?yàn)閿?shù)字簽名的存在,這些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘鑰對(duì)進(jìn)行簽名。
說明:傳統(tǒng)的鑒權(quán)機(jī)制是基于session-cookies,而隨著認(rèn)證用戶的增多,服務(wù)端的開銷會(huì)明顯增大,且不適合做app應(yīng)用驗(yàn)證。因?yàn)閍pp是一次登錄,退出后不需登錄,所以現(xiàn)在主流的鑒權(quán)驗(yàn)證都是使用token驗(yàn)證。而jwt是一種不錯(cuò)的基于token的鑒權(quán)機(jī)制。
基本流程:
用戶使用用戶名密碼來請(qǐng)求服務(wù)器
服務(wù)器進(jìn)行驗(yàn)證用戶的信息
服務(wù)器通過驗(yàn)證發(fā)送給用戶一個(gè)token
客戶端存儲(chǔ)token,并在每次請(qǐng)求時(shí)附送上這個(gè)token值
服務(wù)端驗(yàn)證token值,并返回?cái)?shù)據(jù)
推文:http://www.jianshu.com/p/576dbf44b2ae
3.RestFul
定義:網(wǎng)絡(luò)應(yīng)用程序,分為前端和后端兩個(gè)部分。當(dāng)前的發(fā)展趨勢(shì),就是前端設(shè)備層出不窮(手機(jī)、平板、桌面電腦、其他專用設(shè)備......)。因此,必須有一種統(tǒng)一的機(jī)制,方便不同的前端設(shè)備與后端進(jìn)行通信。這導(dǎo)致API構(gòu)架的流行,甚至出現(xiàn)"API First"的設(shè)計(jì)思想。RESTful API是目前比較成熟的一套互聯(lián)網(wǎng)應(yīng)用程序的API設(shè)計(jì)理論。
說明:restful風(fēng)格,就是一種面向資源服務(wù)的API設(shè)計(jì)方式,它不是規(guī)范,不是標(biāo)準(zhǔn),它一種設(shè)計(jì)模式。以前流行的web service服務(wù)都是面向過程,基于RPC協(xié)議的SOAP協(xié)議,對(duì)于現(xiàn)在或者未來,更多的人了解并且深受SOA思想影響,以面向服務(wù)為目標(biāo),而現(xiàn)在的SOAP雖然支持SOA,但存在很很大的差別,所以,慢慢就流行基于restful風(fēng)格的web service。說簡單一點(diǎn),就是它純粹面向資源,面向服務(wù)的思想,目前J2EE6的JAX-RS就是這種restful風(fēng)格實(shí)現(xiàn)的新技術(shù)。
例子:
獲取用戶列表 GET:http://project.company.com/api/v1/users
獲取單個(gè)用戶 GET:http://project.company.com/api/v1/users/{uid:.{32}}
創(chuàng)建單個(gè)用戶 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}}
刪除單個(gè)用戶 DELETE:http://project.company.com/api/v1/users/{uid:.{32}}
4.Swagger UI
定義:Swagger的目標(biāo)是為REST APIs 定義一個(gè)標(biāo)準(zhǔn)的,與語言無關(guān)的接口,使人和計(jì)算機(jī)在看不到源碼或者看不到文檔或者不能通過網(wǎng)絡(luò)流量檢測(cè)的情況下能發(fā)現(xiàn)和理解各種服務(wù)的功能。當(dāng)服務(wù)通過Swagger定義,消費(fèi)者就能與遠(yuǎn)程的服務(wù)互動(dòng)通過少量的實(shí)現(xiàn)邏輯。類似于低級(jí)編程接口,Swagger去掉了調(diào)用服務(wù)時(shí)的很多猜測(cè)。
說明:swagger ui用于管理項(xiàng)目中API接口,屬當(dāng)前最流行的API接口管理工具。是后端開發(fā)人員提供給app開發(fā)人員的一個(gè)查看、測(cè)試、的一個(gè)可視化,可操作的接口文檔,在這里你可以知道需要給都太傳入什么參數(shù),使用哪種請(qǐng)求,以及返回的數(shù)據(jù)等等,這種就省去app端人員寫測(cè)試接口。
圖示:
代碼:
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驗(yàn)證通過,生成token并返回
c:app端接收到token存起來,下去請(qǐng)求放在reuqest的header里面
d:server接收到app的請(qǐng)求,在攔截器中判斷url是否為需要鑒權(quán)的路徑,然后去驗(yàn)證token
e:當(dāng)token過期時(shí),且沒有超過刷新期。自動(dòng)添加一個(gè)新的token返回給app
攔截器:
public abstract class BaseWebInterceptor extends HandlerInterceptorAdapter {public static final String RedirectPrefix = "redirect:";private static Logger log = LoggerFactory.getLogger(BaseWebInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (isNeedJwtUrl(request.getRequestURI())) { //判斷這個(gè)url是否需要jwt驗(yàn)證 ,比如login就不需要String token = request.getHeader("x-access-token"); //從request中獲取token,key是自定義的,當(dāng)然app端存也要是這個(gè)keyETokenState state = JwtUtil.validateJWT(token); //驗(yàn)證token,ETokenState這是我自定義的一個(gè)類,JwtUtil這也是自己寫的一個(gè)類switch (state) { case invalid: //驗(yàn)證錯(cuò)誤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);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {super.afterCompletion(request, response, handler, ex);}@Overridepublic 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是不攔截的,自己可以配置。關(guān)于jwt生成和驗(yàn)證的代碼,請(qǐng)點(diǎn)擊這里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資源重定向(僅作為后臺(tái)使用不提供靜態(tài)資源) --><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 {@Beanpublic Docket api(){ParameterBuilder tokenPar = new ParameterBuilder();List<Parameter> pars = new ArrayList<Parameter>();//增加一個(gè)request的header參數(shù)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/.*"))//對(duì)所有請(qǐng)求中包含api的url攔截.build().globalOperationParameters(pars).apiInfo(apiInfo());}private ApiInfo apiInfo() {return new ApiInfoBuilder().title("后臺(tái)接口文檔與測(cè)試").description("這是一個(gè)給app端人員調(diào)用server端接口的測(cè)試文檔與平臺(tái)").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 {@AutowiredUserSO so;@ApiOperation(value="驗(yàn)證密文,并添加user", notes="密文和amigoInfo")@RequestMapping( value = {"/login"}, method = RequestMethod.POST, produces = "application/json;charset=UTF-8")@ResponseBodypublic String login(HttpServletRequest request, @RequestParam String fields, @PathVariable String useruid) {// do something}/**api開頭的注解都是swagger的注解*方法參數(shù)上加有@RequestParam的參數(shù)會(huì)顯示在swagger*所以上述login方法的三個(gè)參數(shù)只有fields會(huì)顯示在swagger中*當(dāng)然還有一個(gè)請(qǐng)求頭的參數(shù),存放token的那是在SaggerConfig.java中配置的*/ }4,放開swagger的url不攔截
當(dāng)你配置了jwt,因?yàn)閖wt對(duì)url進(jìn)行攔截,這里我們不能對(duì)swagger的URL進(jìn)行攔截,這樣頁面才能正常顯示。只整合swaggerui的可以忽略。
noNeedJwtUrls=.*swagger.*|.*docs.*|.*test.*|.*/index.*|.*/register.*|.*/login.*至此,swaggerui已配置完成,請(qǐng)求訪問http://localhost:8080/proj-name/swagger-ui.html即可得到以下頁面
3.RestFul API
請(qǐng)參照以下這種方式來定義接口
獲取用戶列表 GET:http://proj.company.com/api/v1/users
獲取單個(gè)用戶 GET:http://proj.company.com/api/v1/users/{uid:.{32}}
創(chuàng)建單個(gè)用戶? 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}}
刪除單個(gè)用戶 DELETE:http://proj.company.com/api/v1/users/{uid:.{32}}
至此,所有配置應(yīng)該都已經(jīng)貼出,代碼可在這里查找:https://github.com/minchangchen/springmvc-jwt-swaggerui。
若有遺失或錯(cuò)誤希望大家提出!過段時(shí)間我會(huì)寫一些與docker有關(guān)的教程,這段時(shí)間覺得自己對(duì)docker的使用還不夠全及精,所以暫時(shí)不寫!
總結(jié)
以上是生活随笔為你收集整理的SpringMVC+JWT+Swagger UI+RestFul的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nfs服务启动失败:Failed to
- 下一篇: Spring及SpringBoot @A