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的使用还不够全及精,因此暂时不写!

相关文章
相关标签/搜索
本站公众号
   欢迎关注本站公众号,获取更多信息