1、使用jjwt的jar包,依赖注入
io.jsonwebtoken
jjwt
0.9.1
2、数据库建表存放用户token
CREATE TABLE `g_user_token` (
`TOKEN_ID` INT NOT NULL AUTO_INCREMENT COMMENT 'tokenID',
`USER_ID` INT NOT NULL COMMENT '用户ID',
`USER_TOKEN` VARCHAR(200) NULL COMMENT '用户TOKEN',
`BUILD_TIME` DATETIME DEFAULT NULL COMMENT '构建时间',
PRIMARY KEY (`TOKEN_ID`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='用户token表';
3、相应实体类,MAPPER及数据库层省略
public class UserToken {
private Integer tokenId;
private Integer userId;
private String userToken;
private Date buildTime;
public Integer getTokenId() {
return tokenId;
}
public void setTokenId(Integer tokenId) {
this.tokenId = tokenId;
}
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getUserToken() {
return userToken;
}
public void setUserToken(String userToken) {
this.userToken = userToken;
}
public Date getBuildTime() {
return buildTime;
}
public void setBuildTime(Date buildTime) {
this.buildTime = buildTime;
}
}
4、拦截器
public class TokenInterceptor implements HandlerInterceptor {
@Autowired
private UserTokenBusinessService userTokenBusinessService;
//提供查询
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {}
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {}
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
//登录路径放行
if ("/admin/login".equals(arg0.getRequestURI()) || "/web/login".equals(arg0.getRequestURI())) {
return true;
}
//权限路径拦截
ServletOutputStream opStream=arg1.getOutputStream();
final String headerToken=arg0.getHeader("Authorization");
//判断请求信息
if(null==headerToken||headerToken.trim().equals("")){
opStream.println("You don't have token and need to login");
arg1.setStatus(401);//token为空,需要登录
return false;
}
//解析Token信息
try {
Claims claims = Jwts.parser().setSigningKey("PROTGAS.D.ACE").parseClaimsJws(headerToken).getBody();
String tokenUserId=(String)claims.get("userId");
int userId=Integer.parseInt(tokenUserId);
//根据客户Token查找数据库Token
UserToken userToken=userTokenBusinessService.selectByPrimaryKey(userId);
String myToken = userToken.getUserToken();
//数据库没有Token记录
if(null==myToken) {
opStream.println("I don't have your token and need to login");
arg1.setStatus(401);//token为空,需要登录
return false;
}
//数据库Token与客户Token比较
if( !myToken.equals(headerToken) ){
opStream.println("Your token has been modified and need to login");
arg1.setStatus(402);//token不对,需要登录
return false;
}
//判断Token过期
Date tokenDate=(Date)claims.getExpiration();
int chaoshi=(int)(new Date().getTime()-tokenDate.getTime());
if(chaoshi>1000*60*30){
opStream.println("Your token is expired and need to login");
arg1.setStatus(403);//token过期,需要登录
return false;
}
} catch (Exception e) {
e.printStackTrace();
opStream.println("Token is not right and need to login");
arg1.setStatus(404);
return false;
}
return true;
}
}
5、配置拦截器
@Configuration
public class TokenConfiguration extends WebMvcConfigurerAdapter{
@Bean
TokenInterceptor tokenInterceptor() {
return new TokenInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry ){
registry.addInterceptor(tokenInterceptor()).addPathPatterns("/**");
}
}
6、登录验证逻辑
public interface LoginService {
public String login(Map<String,Object> params,HttpServletRequest request);
public String logout(Map<String,Object> params,HttpServletRequest request);
}
@Service
public class LoginServiceImpl implements LoginService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RedisSentinelUtil redisUtils;
@Autowired
private UserBusinessService userBusinessService;
@Autowired
private UserTokenBusinessService userTokenBusinessService;
@Autowired
private UserLoginRecordBusinessService userLoginRecordBusinessService;
@Override
public String login(Map params,HttpServletRequest request){
Map data = new HashMap();
String userName = (String)params.get("userName");//登录账户
String passWord = (String)params.get("passWord");//登录密码
String key=userName+"_"+"QT";
String count=redisUtils.getValue(key);
Map map = new HashMap();
map.put("loginId", userName);
User user = userBusinessService.selectByLoginId(map);
if(UtilTools.notNullAndEmpty(count) && Integer.parseInt(count)>=3){//密码错误三次则不让请求
saveMsg(request,user!=null?user.getUserId():null,Constant.USER_STATE_04);
return FastJsonUtils.resultError(-100, "用户被锁定,请十分钟后再尝试", data);
}
if(!passWord.equals(user.getPassword())){
//根据key获取用户登陆密码错误次数
if(UtilTools.notNullAndEmpty(count)){
int count_all=Integer.parseInt(count)+1;
if(count_all == 3){
//redisUtils.removeValue(key);
redisUtils.setCachesData(key, String.valueOf(count_all));
redisUtils.setExpireData(key, 600);
}else if(count_all == 2){
//redisUtils.removeValue(key);
redisUtils.setCachesData(key, String.valueOf(count_all));
}
}else{
redisUtils.setCachesData(key, "1");
}
saveMsg(request,user!=null?user.getUserId():null,Constant.USER_STATE_03);
return FastJsonUtils.resultError(-100, "用户名或密码错误", data);
}
//目前处于登录状态
Map parMap=new HashMap<>();
parMap.put("userId", user.getUserId());
List list=userLoginRecordBusinessService.selectUserLoginRecord(parMap);
if(list!=null && list.size()>0){
UserLoginRecord ulr=list.get(0);
int second=UtilTools.secondBetween(ulr.getLoginTime(), UtilTools.getSysLongDate());
if(UtilTools.nullOrEmpty(ulr.getLogoutTime()) && second<5){
saveMsg(request,user!=null?user.getUserId():null,Constant.USER_STATE_05);
return FastJsonUtils.resultError(5, "目前处于登录状态,请稍后再试", data);
}
}
//登录成功
if(UtilTools.notNullAndEmpty(count)){
redisUtils.removeValue(key);
}
saveMsg(request,user!=null?user.getUserId():null,Constant.USER_STATE_01);//登录记录
String tokenStr = checkUserToken(user);//生成token
data.put("userName", user.getUserName());
data.put("currLoginId", userName);
data.put("token", tokenStr);
return FastJsonUtils.resultSuccess(200, "登录成功", data);
}
@Override
public String logout(Map params,HttpServletRequest request){
return FastJsonUtils.resultSuccess(200, "退出成功", null);
}
/**
* 记录用户登陆信息
*/
public void saveMsg(javax.servlet.http.HttpServletRequest request,Integer userId,String userState){
UserLoginRecord userLoginRecord=new UserLoginRecord();
userLoginRecord.setLoginTime(UtilTools.getSysLongDate());
userLoginRecord.setServerIp(request.getLocalAddr());
userLoginRecord.setUserId(userId);
userLoginRecord.setUserState(userState);
userLoginRecordBusinessService.insertSelective(userLoginRecord);
}
//用户Token信息
private String checkUserToken(User user) {
//根据数据库的用户信息查询Token
UserToken userToken = userTokenBusinessService.selectByPrimaryKey(user.getUserId());
//为生成Token准备
String tokenStr = "";
Date date = new Date();
//生成Token
if (null == userToken) {
//第一次登陆
tokenStr = creatToken(user, date);
userToken = new UserToken();
userToken.setUserToken(tokenStr);
userToken.setBuildTime(date);
userToken.setUserId(user.getUserId());
userTokenBusinessService.insert(userToken);
}else{
//登陆就更新Token信息
tokenStr = creatToken(user, date);
userToken.setUserToken(tokenStr);
userToken.setBuildTime(date);
userTokenBusinessService.update(userToken);
}
return tokenStr;
}
//生成Token信息方法(根据有效的用户信息)
private String creatToken(User user, Date date) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT") // 设置header
.setHeaderParam("alg", "HS256").setIssuedAt(date) // 设置签发时间
.setExpiration(new Date(date.getTime() + 1000 * 60 * 30))// 过期时间半小时
.claim("userId",String.valueOf(user.getUserId()) ) // 设置内容
.setIssuer("Dzhy")// 设置签发人
.signWith(signatureAlgorithm, "PROTGAS.D.ACE"); // 签名,需要算法和key
String jwt = builder.compact();
return jwt;
}
}
@RestController
@RequestMapping("/admin")
@Api(value = "LoginController", description="后管系统登录接口")
public class LoginAdminController {
@Autowired
private LoginService loginService;
@Autowired
private UserBusinessService userBusinessService;
/**
* 登录
* @param record
* @param request
* @return
*/
@ApiOperation(value = "登录", notes = "登录")
@ApiImplicitParams({@ApiImplicitParam(name = "record", required=true, dataType = "SysAdminUser") })
@PostMapping(value = "/login", produces = {"application/json;charset=UTF-8"})
public String login(@RequestBody Map<String,Object> params,HttpServletRequest request) {
Map<String, Object> data = new HashMap<String, Object>();
//做简单校验一
String userName = (String)params.get("userName");
String passWord = (String)params.get("passWord");
if(null == userName || "".equals(userName)
|| null == passWord || "".equals(passWord)){){
return FastJsonUtils.resultError(-100, "账号不能为空", null);
}
//做简单校验二
Map<String, Object> map = new HashMap<String, Object>();
map.put("loginId", userName);
User user = userBusinessService.selectByLoginId(map);
if(null == user){//用户不存在
return FastJsonUtils.resultError(-100, "用户名或密码错误", data);
}else if("F".equals(user.getOnJob())){
return FastJsonUtils.resultError(-100, "帐号已被禁用", data);
}
//自定义校验三
return loginService.login(params, request);
}
}