jpassport是根据token机制实现的登录权限校验模块。经历了大型社交网络的生产环境考验,能应对高并发场景,可以集群化部署
Passport for Java project via userId and token
GitHub地址为https://github.com/liushaoming/jpassport
建议访问GitHub以获取作者的更多分布式项目源码https://github.com/liushaoming?tab=repositories
jseckill是怎么诞生的?
作者liushaoming 之前在做公司的一个大型社交类App后台项目中,开发了这个登录模块。当时是用Spring MVC做的,
后来开源出来,现在改成了最新的Spring Boot2.X 。经过大型社交网络系统的高并发场景的长期考验。说明了
jseckill能够支撑起大型互联网项目
为什么需要token机制来进行权限校验呢?
在分布式环境中,因为站点是集群的,不可能使用tomcat的session来保存用户的登录状态。微服务架构也需要
做成无状态的服务,这就需要token机制来做用户权限校验了。
这里,基于Spring的Interceptor来拦截指定的需要权限验证的
Controller里的method,去校验userId + token。就可以实现它。
1.Spring + Spring Boot 2.X + MyBatis. 可用于SpringMVC或者SpringBoot项目
2.maven3.0
3.Jdk1.8+
4.mysql或者其他的数据库
5.Redis
如何使用jpassport-lib库,参考项目jpassport-web
Usage:
Step1:
git clone https://github.com/liushaoming/jpassport.git
Step2: 安装fpassport-lib.jar到本地的maven仓库
进入fpassport-lib目录
cd jpassport-lib
mvn install
Step3: 在你自己的SpringMVC或者SpringBoot项目中引用fpassport-lib.jar
在自己的项目的pom.xml中增加下面的依赖
<dependency>
<groupId>com.appjishu</groupId>
<artifactId>jpassport-lib</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
Step4. 数据库建表SQL在doc/db/xxx.sql
根据fly_token.sql和fly_user.sql建立两个表fly_token和fly_user
把flylib-site里面的resources/property/jdbc.properties和redis.properties改成自己的数据库和redis配置
Step5. 启动jpassport-web项目(或者你自己的项目) 在IDEA/eclipse里,找到jpassport-web下的App.java, 右键--Debug
打开浏览器,访问
http://localhost:20100/
正常情况,浏览器会显示文本如下
this is jpassport home page.
下面是一些测试url
注册账号--
http://localhost:20100/passport/register?username=13011111111&password=123456&accountType=1
用手机号作为用户名登录,并获取token--
http://localhost:20100/passport/login?username=13011111111&password=123456&accountType=1
登录成功后,后台会返回token给前端, 前端调用任何需要认证的所有http接口都需要在请求头(headers)带上参数userId和token
例如--
url: http://localhost:20100/account/getInfo
type: post
headers:
userId=5
token=069473bedcc609b0d25d6746c11760e5
你可以用postman来测试,效果图如下
核心原理概述 使用Spring Web的Interceptor来拦截http request里的header里的参数userId,token
后台认证, 对比存在Redis中的token (持久化到了MySQL里)
token,在注册时候生成,在用户修改密码后,token会被后台更新,踢掉别的客户端操作。
token存在Redis里,适合分布式认证的场景。属于轻量级的可靠认证。
使用了注解code>@AuthController</code
同时使用了org.flylib.passport.intercepter.LoginInterceptor
LoginInterceptor的主要代码
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
logger.info("进入拦截器...........");
Object controller = handlerMethod.getBean();
printParameters(request, controller);
// 访问需要登录的接口那些
// 被@AuthController注解的Controller
boolean present = controller.getClass().isAnnotationPresent(AuthController.class);
if (!present) {
return true;
}
String userIdStr = request.getHeader("userId");
String token = request.getHeader("token");
if (!StringUtils.isEmpty(userIdStr)) {
logger.info("访问需要登录的接口(Authed)...........");
if (StringUtils.isEmpty(token)) {
flushError(response, AuthResponseCode.TOKEN_IS_NULL, AuthResponseCode.TOKEN_IS_NULL_DESC);
return false;
}
Passport passport = loginIntercepterService.getPassport(Long.valueOf(userIdStr));
String storedToken = passport.getToken();
if (StringUtils.isEmpty(storedToken)) {
flushError(response, AuthResponseCode.TOKEN_EXPIRED, AuthResponseCode.TOKEN_EXPIRED_DESC);
return false;
} else if (!storedToken.equals(token)) {
flushError(response, AuthResponseCode.TOKEN_INVALID, AuthResponseCode.TOKEN_INVALID_DESC);
return false;
}
} else {
flushError(response, AuthResponseCode.USER_ID_IS_NULL, AuthResponseCode.USER_ID_IS_NULL_DESC);
return false;
}
// 被@AuthController注解的 结束
}
boolean flag = isPermission(request, response);
logger.info("isPermission:" + flag);
return flag;
}
会去判断客户端当前访问的Controller是否被code>@AuthController</code注解
如果被它注解,了就会进入权限鉴定逻辑。
鉴权逻辑,会提取http headers里面的userId和token值。
后台根据userId去redis查询正确的token(如果没有就去数据库中查询,redis提高了访问数据速度)
如果存储的token跟header里的token相等,则LoginInterceptor给与放行,继续执行MVC里的业务逻辑;
否则,拒绝放行,就是直接把报错的code和codeDes描述以json字符串返回给http客户端。
本来可以放在http parameter(http body)里。 因为http参数里面可能有很多用户自己的参数
都放在一起会比较混乱。 比较规范的做法是把这些权限认证之类的放在请求头headers里
http客户端,需要存放在cookie中,每次请求的时候,需要从cookie中读取;
Android客户端,可以存放在SharedPreferences里面;
因为Spring Boot适合快速构建Spring应用。 而且这里及时更新到Spring Boot 2.X。 免去了获取代码的程序员自己去升级。开箱即用。
联系方式 | |
---|---|
Leader | liushaoming |
liushaomingdev@163.com | |
944147540 |
有代码改进优化的建议的统一在Issues里面提
加群讨论