用户登录验证token

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);
	}
}

你可能感兴趣的:(用户登录验证token)