我的视频课程(基础):《(NDK)FFmpeg打造Android万能音频播放器》
我的视频课程(进阶):《(NDK)FFmpeg打造Android视频播放器》
我的视频课程(编码直播推流):《Android视频编码和直播推流》
目录:
移动大脑-SpringMVc搭建RestFul后台服务(一)-环境搭建
移动大脑-SpringMVc搭建RestFul后台服务(二)-配置mysql数据库
移动大脑-SpringMVc搭建RestFul后台服务(三)-RestFul接口编写(模拟用户注册登录)
移动大脑-SpringMVc搭建RestFul后台服务(四)-添加Token拦截器
移动大脑-SpringMVc搭建RestFul后台服务(五)-支付宝支付
移动大脑-SpringMVc搭建RestFul后台服务(六)-微信支付(Android)
移动大脑-SpringMVc搭建RestFul后台服务(七)-增量更新
在第三篇博客《移动大脑-SpringMVc搭建RestFul后台服务(三)-RestFul接口编写(模拟用户注册登录)》中我们已经可以通过客户端访问服务端数据了,现在还需要添加Token验证功能来达到一定的安全性,此时就需要用到拦截器——HandlerInterceptor。
一、添加TokenBean.java实体类和表t_token
package com.ywl5320.appservice.bean;
/**
* Created by ywl5320 on 2017/10/13.
*/
public class TokenBean extends BaseBean{
private Integer id;
private String phone;
private String token;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
在entitis.hbm.xml中配置表t_token:
<class name="com.ywl5320.appservice.bean.TokenBean" table="t_token">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="phone" column="phone"></property>
<property name="token" column="token"></property>
</class>
二、添加TokenDao.java和TokenDaoImpl.java
TokenDao.java
package com.ywl5320.appservice.dao;
import com.ywl5320.appservice.bean.TokenBean;
/**
* Created by ywl5320 on 2017/10/13.
*/
public interface TokenDao {
/**
* 登录或注册时写入token
* @param tokenBean
*/
void saveOrUpdageToken(TokenBean tokenBean);
/**
* 根据电话号码获取token
* @param phone
* @return
*/
TokenBean isTokenAvailable(String phone);
}
TokenDaoImpl.java
package com.ywl5320.appservice.dao;
import com.ywl5320.appservice.bean.TokenBean;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import java.util.List;
/**
* Created by ywl5320 on 2017/10/13.
*/
public class TokenDaoImpl extends HibernateDaoSupport implements TokenDao{
public void saveOrUpdageToken(TokenBean tokenBean) {
this.getHibernateTemplate().saveOrUpdate(tokenBean);
}
public TokenBean isTokenAvailable(String phone) {
List<TokenBean> tokens = (List<TokenBean>) this.getHibernateTemplate().find("from TokenBean where phone=?", phone);
if(tokens != null && tokens.size() > 0)
{
return tokens.get(0);
}
return null;
}
}
这样存储token和获取token都完成了。
最后配置TokenDaoImplement到beans.xml中
<bean id="tokenDaoImpl" class="com.ywl5320.appservice.dao.TokenDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
三、拦截器的编写,客户端把token、phone等信息放在header里面,服务端在收到请求的第一步就先判断header中token和phone是否匹配,然后做相应的处理:
RestFulInterceptor.java
package com.ywl5320.appservice.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.ywl5320.appservice.bean.RestFulBean;
import com.ywl5320.appservice.bean.TokenBean;
import com.ywl5320.appservice.dao.TokenDao;
import com.ywl5320.appservice.util.RestFulUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Writer;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* Created by ywl5320 on 2017/10/16.
*/
public class RestFulInterceptor implements HandlerInterceptor {
@Autowired
private TokenDao tokenDao;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
// TODO Auto-generated method stub
String uri = request.getRequestURI();
Map<String, String> headerMaps = new HashMap<String, String>();
Enumeration headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String key = (String) headerNames.nextElement();
String value = request.getHeader(key);
headerMaps.put(key, value);
}
if(!uri.endsWith(".do"))
{
return true;
}
if(uri.endsWith("user/loginbypwd.do"))//登录
{
return true;
}
else if(uri.endsWith("user/register.do"))//注册
{
return true;
}
else if(uri.endsWith("pay/verifyalipayresult.do"))//支付验证(暂留)
{
return true;
}
else
{
TokenBean tokenBean = tokenDao.isTokenAvailable(headerMaps.get("phone"));
if(tokenBean != null && tokenBean.getToken().equals(headerMaps.get("token")))
{
return true;
}
else
{
RestFulBean<TokenBean> resuFulBean = RestFulUtil.getInstance().getResuFulBean(null, 1, "用户身份验证失败");
response.setCharacterEncoding("UTF-8");
Writer writer = response.getWriter();
writer.write(JSONObject.toJSONString(resuFulBean, SerializerFeature.WriteMapNullValue));
return false;
}
}
}
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
}
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
}
}
验证里面有登录和注册接口不需要验证,其他不是以.do结尾的也不需要验证(可根据时间情况调整),还有支付回调(后面添加)也不需要验证。
最后在springmvc.xml中配置拦截器:
<mvc:interceptors>
<bean class="com.ywl5320.appservice.interceptor.RestFulInterceptor"/>
</mvc:interceptors>
四、在Service的注册和登录接口中生成和返回token并添加一个需要验证Token的获取用户详情的接口用来测试。
UserService.java
package com.ywl5320.appservice.service;
import com.ywl5320.appservice.bean.RestFulBean;
import com.ywl5320.appservice.bean.TokenBean;
import com.ywl5320.appservice.bean.UserBean;
import com.ywl5320.appservice.dao.TokenDao;
import com.ywl5320.appservice.dao.UserDao;
import com.ywl5320.appservice.util.MD5;
import com.ywl5320.appservice.util.RestFulUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
/**
* Created by ywl5320 on 2017/10/12.
*/
@Transactional
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private TokenDao tokenDao;
public RestFulBean<UserBean> registorServer(UserBean userBean)
{
UserBean user = userDao.getUser(userBean.getPhone());
if(user != null)
{
return RestFulUtil.getInstance().getResuFulBean(null, 1, "已经注册过了");
}
else
{
user = userDao.registor(userBean);
if(user != null)
{
saveOrUpdateToken(user);
return RestFulUtil.getInstance().getResuFulBean(user, 0, "注册成功");
}
else{
return RestFulUtil.getInstance().getResuFulBean(null, 1, "注册失败");
}
}
}
public RestFulBean<UserBean> login(String phone, String password)
{
UserBean user = userDao.login(phone, password);
if(user != null)
{
saveOrUpdateToken(user);
return RestFulUtil.getInstance().getResuFulBean(user, 0, "登录成功");
}
else
{
return RestFulUtil.getInstance().getResuFulBean(null, 1, "用户不存在");
}
}
public RestFulBean<UserBean> userinfo(String phone)
{
UserBean userBean = userDao.getUser(phone);
if(userBean != null)
{
return RestFulUtil.getInstance().getResuFulBean(userBean, 0, "获取成功");
}
return RestFulUtil.getInstance().getResuFulBean(null, 1, "用户不存在");
}
private void saveOrUpdateToken(UserBean userBean){
String token = null;
try {
token = MD5.encryptMD5(String.valueOf(System.currentTimeMillis()) + "appservice.02154778ke783dad34");
} catch (Exception e) {
e.printStackTrace();
}
userBean.setToken(token);
TokenBean tokenBean = tokenDao.isTokenAvailable(userBean.getPhone());
if(tokenBean != null)
{
tokenBean.setToken(token);
}
else
{
tokenBean = new TokenBean();
tokenBean.setPhone(userBean.getPhone());
tokenBean.setToken(userBean.getToken());
}
tokenDao.saveOrUpdageToken(tokenBean);
}
}
五、UserAction中添加Get方法获取用户详情
/**
* 详情
* @param phone
* @return
*/
@ResponseBody
@RequestMapping(value="/userinfo.do", method= RequestMethod.GET)
public RestFulBean<UserBean> userInfo(String phone)
{
System.out.println("phone:" + phone);
return userService.userinfo(phone);
}
以上就为服务端的接口添加了Token的拦截器,达到了一定的安全性,这里没有设定token的过期时间,可以再加一个token过期时间(实际情况主要还是根据需求来)。
六、最后用客户端测试一下(客户端是基于我的另一个GitHubRxjavaRetrofit 项目修改而来的):
6.1:当没有登录时获取详情,此时token为空,验证失败
由于是get请求,我们也可以直接在浏览器中测试:
结果表明还是不能通过身份验证。
6.2执行用户登录操作:
测试表明登录接口能正常访问,并没有验证并返回了token给客户端,注册和支付回调接口也是一样的不用验证。
6.3、再执行获取详情接口
现在就可以正常获取用户数据了。
源码下载:GitHub AppServiceRestFul
这样一个完整的RestFul实例就完成了配合客户端就能完成一个功能健全的应用程序了。
接下来几篇博客来提高一下综合功能(支付、增量更新等)。