1. 为何使用Restful API
  1. Restful是什么?
RESTful(Representational State Transfer)架构风格,是一个Web自身的架构风格,底层主要基于HTTP协议(ps:提出者就是HTTP协议的作者),是分布式应用架构的伟大实践理论。RESTful架构是无状态的,表现为请求-响应的形式,有别于基于Bower的SessionId不同。
  1. 理解REST有五点:
1.资源 
2.资源的表述 
3.状态的转移 
4.统一接口 
5.超文本驱动
  1. 什么是REST API
基于RESTful架构的一套互联网分布式的API设计理论。和上面资源,状态和统一接口有着密切的关系。
  1. 权限控制:前面说到,RESTful是无状态的,所以每次请求就需要对起进行认证和授权
  • 认证:身份认证,即登录验证用户是否拥有相应的身份。简单的说就是一个Web页面点击登录后,服务端进行用户密码的校验。
  • 权限验证(授权):也可以说成授权,就是在身份认证后,验证该身份具体拥有某种权限。即针对于某种资源的CRUD,不同用户的操作权限是不同的。
一般简单项目:做个sign(加密加盐参数)+ 针对用户的access_token。
复杂的话,加入 SLL ,并使用OAuth2进行对token的安全传输。
  1. Access Token权限解决
  1. AccessToken 拦截器:
/**
 * Access Token拦截器
 * <p/>
 * Created by bysocket on 16/4/18.
 */
@Component
public class AccessTokenVerifyInterceptor extends HandlerInterceptorAdapter {
 
    @Autowired
    ValidationService validationService;
 
    private final static Logger LOG = LoggerFactory.getLogger(AccessTokenVerifyInterceptor.class);
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        LOG.info("AccessToken executing ...");
        boolean flag = false;
        // token
        String accessToken = request.getParameter("token");
        if (StringUtils.isNotBlank(accessToken)) {
            // 验证
            ValidationModel v = validationService.verifyAccessToken(accessToken);
            // 时间过期
 
            // 用户验证
            if (v != null) {
                User user = userService.findById(v.getUid());
                if(user != null) {
                    request.setAttribute(CommonConst.PARAM_USER, user);
                    LOG.info("AccessToken SUCCESS ...  user:" + user.getUserName() + " - " + accessToken);
                    flag = true;
                }
            }
        }
 
        if (!flag) {
            response.setStatus(HttpStatus.FORBIDDEN.value());
            response.getWriter().print("AccessToken ERROR");
        }
 
        return flag;
    }
}

第一步:从request获取token

第二步:根据token获取校验对象信息(也可以加入过期时间校验,简单)

第三步:通过校验信息获取用户信息
  • Spring MVC中的拦截器/过滤器HandlerInterceptorAdapter
应用场景
1、日志记录,可以记录请求信息的日志,以便进行信息监控、信息统计等。
2、权限检查:如登陆检测,进入处理器检测是否登陆,如果没有直接返回到登陆页面。
3、性能监控:典型的是慢日志。
  • 该类是一个抽象类,它实现了AsyncHandlerInterceptor接口
public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor

public interface AsyncHandlerInterceptor extends HandlerInterceptor {
 
	/**
	 * Called instead of {@code postHandle} and {@code afterCompletion}, when
	 * the a handler is being executed concurrently. Implementations may use the
	 * provided request and response but should avoid modifying them in ways
	 * that would conflict with the concurrent execution of the handler. A
	 * typical use of this method would be to clean thread local variables.
	 *
	 * @param request the current request
	 * @param response the current response
	 * @param handler handler (or {@link HandlerMethod}) that started async
	 * execution, for type and/or instance examination
	 * @throws Exception in case of errors
	 */
	void afterConcurrentHandlingStarted(
			HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception;
 
}
  • 进一步查看源码发现该接口继承了HandlerInterceptor接口
public interface HandlerInterceptor {

   /**
     * 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
     * 返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
   */
    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;

   /**
     * 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
   */
    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;

   /**
    * 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中
   */
    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;

}
  1. 配置拦截:
/**
 * MVC 设置
 *
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
 
    @Bean
    public AccessTokenVerifyInterceptor tokenVerifyInterceptor() {
        return new AccessTokenVerifyInterceptor();
    }
 
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenVerifyInterceptor()).addPathPatterns("/test");
        super.addInterceptors(registry);
    }
 
}

第一步:将拦截器配置成Bean

第二步:拦截器注册注入该拦截器,并配置拦截的URL
  • SpringBoot配置类WebMvcConfigurerAdapter:
WebMvcConfigurerAdapter配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制
  • 创建一个配置实体类型,并继承WebMvcConfigurerAdapter
  • WebMvcConfigurerAdapter该抽象类其实里面没有任何的方法实现,只是空实现了接口WebMvcConfigurer内的全部方法,并没有给出任何的业务逻辑处理,这一点设计恰到好处的让我们不必去实现那些我们不用的方法,都交由WebMvcConfigurerAdapter抽象类空实现,如果我们需要针对具体的某一个方法做出逻辑处理,仅仅需要在WebMvcConfigurerAdapter子类中@Override对应方法就可以了
  • 拦截器配置:InterceptorRegistry内的addInterceptor需要一个实现HandlerInterceptor接口的拦截器实例,addPathPatterns方法用于设置拦截器的过滤路径规则
/**
     * 拦截器配置
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        super.addInterceptors(registry);
        registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**");
    }
  1. token存哪里?
ehcache,redis,db都可以。自然简单的当然是db。