package com.terra.proxy.controller; import java.util.*; import javax.servlet.http.HttpServletRequest; import cn.hutool.core.collection.CollectionUtil; import com.terra.proxy.util.JedisUtils; import io.swagger.models.auth.In; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.web.bind.annotation.*; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; import com.terra.proxy.bean.CustomerToken; import com.terra.proxy.bean.ResActionRecord; import com.terra.proxy.bean.TokenRecord; import com.terra.proxy.mapper.LogMapper; import com.terra.proxy.service.Impl.LogServiceImpl; import com.terra.proxy.service.Impl.ResActionRecordServiceImpl; import com.terra.proxy.service.Impl.ServerRegisterServiceImpl; import com.terra.proxy.util.HttpContextUtils; import com.terra.proxy.util.JwtUtils; import com.terra.proxy.util.Result; import cn.hutool.json.JSONUtil; import io.jsonwebtoken.Claims; import redis.clients.jedis.Jedis; /** * token生成与验证 * * @author TanBin * @date 2018年1月31日 下午6:26:13 */ @RestController public class TokenController { @Autowired public Environment env; @Autowired LogServiceImpl logservice; @Autowired ResActionRecordServiceImpl actionRecordService; @Autowired private JwtUtils jwtUtils; @Autowired JedisUtils jedisUtils; @Value("${sys.allowedips}") private String allowedips; @Value("${sys.jwt.expire}") private Long expireSeconds; @Autowired ServerRegisterServiceImpl serverRegisterService; @Autowired LogMapper logMapper; private static final Logger log = LoggerFactory.getLogger(TokenController.class); @RequestMapping(value = "/token/getToken", method = { RequestMethod.POST, RequestMethod.GET }) public String getToken(String message,long expireSeconds) { // 生成token String token = jwtUtils.generateToken( message.toString(), expireSeconds); return token; } @RequestMapping(value="/token/delTokenRecord",method = {RequestMethod.GET,RequestMethod.POST}) @ResponseBody public String delToken(String token,Integer expiration){ Jedis jedis=JedisUtils.getJedis(); String t="zytoken:"+token; try{ Map params =new HashMap<>(); params.put("token", token); params.put("expiration", -1); jedis.del(t); //除去自动续约token jedis.srem("autoToken",token); logservice.updateTokenRecord(params); }catch (Exception e) { e.printStackTrace(); } return "success"; } @RequestMapping(value="/token/selectTokenRecord",method = {RequestMethod.GET,RequestMethod.POST}) @ResponseBody public String selectTokenRecord(Integer limit,Integer page,String token,Integer tokenstatus,String identyinfo,Integer resourceId){ Map params =new HashMap<>(); params.put("limit", limit); params.put("page", (page-1)*limit); params.put("token", token); params.put("tokenstatus", tokenstatus); params.put("identyinfo", identyinfo); params.put("resourceId", resourceId); List list=logservice.selectTokenRecord(params); Jedis jedis = JedisUtils.getJedis(); //自动续约列表 Set autoToken = jedis.smembers("autoToken"); list.stream().forEach(map -> { String string = map.get("TOKEN").toString(); if(StringUtils.isNotEmpty(string)&&autoToken.contains(string)){ map.put("AUTOTOKEN","1"); }else { map.put("AUTOTOKEN","0"); } }); JedisUtils.close(jedis); JSONObject json=new JSONObject(); json.put("total", logservice.getTotalTokenRecord(params)); json.put("data", list); json.put("totalpage",Math.ceil((double) logservice.getTotalTokenRecord(params)/(double)limit)); return JSONObject.toJSONStringWithDateFormat(json, "yyyy-MM-dd HH:mm:ss", SerializerFeature.PrettyFormat); } @RequestMapping(value = "/token/tokenTimeExtend", method = { RequestMethod.POST, RequestMethod.GET }) public String tokenTimeExtend(String tokenlist,Integer expireSeconds) { Jedis jedis= JedisUtils.getJedis(); Map params =new HashMap<>(); if (StringUtils.isEmpty(tokenlist)) return Result.ok().toString(); if(null==expireSeconds) expireSeconds= this.expireSeconds.intValue(); try{ String[] tokens=tokenlist.split(";"); for(String t : tokens){ String token="zyToken:"+t; String s = jedis.get(token); if(StringUtils.isEmpty(s)){ //如果已经过期 重新加入redis 并且更新数据 jedis.setex(token,expireSeconds,"1"); }else { //如果没过期 过期时间加长 Long ttl = jedis.ttl(token); int time=Integer.parseInt(String.valueOf(ttl+expireSeconds)); expireSeconds=time; jedis.setex(token,time,"1"); } params.put("token", t); params.put("expiration", expireSeconds); params.put("applytime", new Date()); logservice.updateTokenRecord(params); } }catch (Exception e){ e.printStackTrace(); }finally { jedis.close(); } return "ok"; } @RequestMapping(value = "/token/decToken", method = { RequestMethod.POST, RequestMethod.GET }) public String decToken(String token) { Claims claims = jwtUtils.getClaimByToken(token); if (claims == null || jwtUtils.isTokenExpired(claims.getExpiration())) { return "token已失效"; } return claims.getSubject(); } /** * 生成用户访问资源服务token * 调用示例:token/generate?loginName=landtoollxb&resourceId=&resourceUrl=&expireSeconds=&clientIp= * * @param userid * @param resourceId * @param expireSeconds * @param clientIp * @param subzyids * @param isPubzy * @return */ private Result generateByloginName(Integer userid, String resourceId, Long expireSeconds, String clientIp,String subzyids,Boolean isPubzy) { if ( userid==0) { return Result.error("缺少userid参数"); } if (StringUtils.isBlank(resourceId)) { return Result.error("缺少resourceId参数"); } if (StringUtils.isBlank(clientIp)) { return Result.error("缺少clientIp参数"); } CustomerToken cutToken=new CustomerToken(); cutToken.setResourceId(resourceId); cutToken.setClientIp(clientIp); cutToken.setUserid(userid.toString()); cutToken.setSubzyids(subzyids); cutToken.setIsPubzy(isPubzy); // 生成token String token = jwtUtils.generateToken( cutToken.toString(), expireSeconds); SaveTokenRecord( expireSeconds, "用户"+userid+"生成", token, cutToken, clientIp); Map map = new HashMap<>(); map.put("token", token); map.put("expire", jwtUtils.getClaimByToken(token).getExpiration()); Result r = Result.ok().put(map); return r; } /** * 系统内部使用 * 生成token * 调用示例:token/generate?loginName=landtoollxb&resourceId=&resourceUrl=&expireSeconds=&clientIp= * * @param userid * @param resourceId * @param expireSeconds * @param clientIp * @param subzyids * @param isPubzy * @return */ @RequestMapping(value = "/token/generate", method = { RequestMethod.POST, RequestMethod.GET }) public Result generate(Integer userid, String resourceId, Long expireSeconds,String clientIp,String subzyids,Boolean isPubzy) { Map msg = new HashMap<>(); //判读IP是否合法------ HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); String ip = request.getLocalAddr(); //判读IP是否合法------ if(!checkIp(ip)) { return Result.error("非法IP调用【"+ip+"】"); } Result r = generateByloginName(userid, resourceId, expireSeconds, clientIp, subzyids,isPubzy); return r; } /** * 系统内部使用 * 生成token * 调用示例:token/appgenerate?resourceId=&resourceUrl=&expireSeconds=&appId=&appUrl= * * @param resourceId * @param resourceId * @param expireSeconds * @param appId * @param appUrl * @return */ @RequestMapping(value = "/token/appgenerate", method = { RequestMethod.POST, RequestMethod.GET }) public Result appGenerate(Integer userId,String resourceId, Long expireSeconds, Long appId, String appUrl,String subzyids) { HttpServletRequest request = HttpContextUtils.getHttpServletRequest(); String clientIp = request.getLocalAddr(); //判读IP是否合法------ if(!checkIp(clientIp)) { return Result.error("非法IP调用【"+clientIp+"】"); } if (StringUtils.isBlank(resourceId)) { return Result.error("缺少resourceId参数"); } if (null == appId) { return Result.error("缺少appId参数"); } if (StringUtils.isBlank(appUrl)) { return Result.error("缺少appUrl参数"); } CustomerToken cutToken=new CustomerToken(); cutToken.setResourceId(resourceId); cutToken.setAppId(appId.toString()); cutToken.setAppUrl(appUrl); cutToken.setUserid( userId.toString()); cutToken.setSubzyids(subzyids); // 生成token String token = jwtUtils.generateToken(cutToken.toString(), expireSeconds); SaveTokenRecord( expireSeconds, "应用系统"+appId+"生成", token, cutToken, clientIp); Map map = new HashMap<>(); map.put("token", token); map.put("expire", jwtUtils.getClaimByToken(token).getExpiration()); Result r = Result.ok().put(map); return r; } /** * "?resourceId=" + resourceId + "&requestUrl=" + requestUrl + "&clientIp=" + clientIp + "&refererUrl=" + referer + "&token=" + token; * 验证token 调用示例:token/validate?token=&requestUrl=&clientip= * 或:token/validate?token=&requestUrl=&refererUrl= * 目前日志记录有问题:loginName在Token里面,记录不到。 * @param token * @param requestUrl * @param clientIp * @param refererUrl * @return */ @RequestMapping(value = "/token/validate", method = { RequestMethod.POST, RequestMethod.GET }) public Result validate(String token, String requestUrl, String clientIp, String refererUrl,String resourceId) { // 校验token if (StringUtils.isBlank(token)) { return Result.error(HttpStatus.SC_UNAUTHORIZED, "未传入token"); } Claims claims = jwtUtils.getClaimByToken(token); if (claims == null || jwtUtils.isTokenExpired(claims.getExpiration())) { return Result.error(HttpStatus.SC_UNAUTHORIZED, "token已失效"); } String msg = claims.getSubject(); CustomerToken cutToken=CustomerToken.fromString(msg); String appId =cutToken.getAppId(); // 无appId属通过浏览器直接访问的情况:校验 clientIp 与 Token里面的IP地址是否匹配, if (StringUtils.isBlank(appId)) { //资源池系统采用APPToken 方式校验,解决专题地图里面图层其他用户访问IP校验不通过问题 //如果本地ArcMap调用资源池里面的图层后发布服务,仍然会存在其他用户访问IP校验不通过问题----lxb(延后解决) log.info("传入IP:"+clientIp +"加密时申请IP:"+(String) cutToken.getClientIp() ); if (StringUtils.isBlank(clientIp) || !clientIp.equalsIgnoreCase((String) cutToken.getClientIp())) { return Result.error(HttpStatus.SC_UNAUTHORIZED, "未授权的客户端"); } // 有appId属通过app访问的情况:校验 refererUrl 与 Token里面的appUrl地址是否匹配 } else { log.info("传入refererUrl:"+refererUrl +"加密时申请appUrl:"+(String) cutToken.getAppUrl() ); if (StringUtils.isBlank(refererUrl) || !refererUrl.startsWith((String) cutToken.getAppUrl())) { return Result.error(HttpStatus.SC_UNAUTHORIZED, "未授权的应用系统"); } } //记录日志 saveLogAction(cutToken,resourceId); //如果是专题底图,并且包含有不公开的图层资源,则返回资源ID列表. Result r = Result.ok(cutToken.getSubzyids() ); return r; } private void saveLogAction(CustomerToken map,String resourceId){ ResActionRecord record = new ResActionRecord(); //解密 Token 里包含userid的取那值,没有取0 Long userid =Long.parseLong( map.getUserid()) ;//")!=null?Long.parseLong(map.get("userId").toString()):0L; record.setUserid(userid); Integer appid =Integer.parseInt( map.getAppId());//map.get("appId")!=null?Integer.parseInt(map.get("appId").toString()):0; record.setAppid(appid); record.setResourceid(resourceId.length()!=0? Integer.parseInt(resourceId):0); actionRecordService.save(record); } private Boolean checkIp(String ip) { Boolean rsult=false ; String whiteIPlist = env.getProperty("whiteIPlist"); if(StringUtils.contains(whiteIPlist, ip)) { rsult=true; } return rsult; } /** * 外部调用 * 临时token获取 * @param resourceid 资源id * @param req * @param expiration 失效时间 * @param identyinfo 备注信息 表明 token使用人 * @param appUrl 申请token系统地址 * @param isPubzy 公开级别 * @param appId 应用id * @param applyuserid token申请人用户id * @return */ @RequestMapping(value = "/genToken", method = RequestMethod.GET) public @ResponseBody String genToken(String resourceid,HttpServletRequest req,Long expiration,String identyinfo,String appUrl,Boolean isPubzy,String appId,String applyuserid ) { String clientIp = req.getLocalAddr(); JSONObject json=new JSONObject(); Jedis jedis = jedisUtils.getJedis(); try { CustomerToken cutToken=new CustomerToken(); cutToken.setResourceId(resourceid); cutToken.setUserid(applyuserid); cutToken.setAppUrl(appUrl); cutToken.setIsPubzy(isPubzy); cutToken.setAppId(appId); cutToken.setClientIp(req.getRemoteHost()); cutToken.setRemark(identyinfo); String token = expiration!=null?jwtUtils.generateToken(cutToken.toString(), expiration):jwtUtils.generateToken(cutToken.toString(), expireSeconds); SaveTokenRecord( expiration, identyinfo, token, cutToken, clientIp); jedis.setex("zytoken:"+token,expiration!=null?expiration.intValue():expireSeconds.intValue(), "1"); json.put("code", 200); json.put("data", token); json.put("message", "获取成功"); return json.toJSONString(); } catch (Exception e) { e.printStackTrace(); } finally { jedis.close(); } return "error"; } /** * 取消自动续约的Token * @param token token值 */ @RequestMapping("/token/delAutoToken") public void delAutoToken(@RequestParam String token){ if(StringUtils.isNotEmpty(token)){ Jedis jedis = JedisUtils.getJedis(); jedis.srem("autoToken",token); JedisUtils.close(jedis); } } /** * 记录生成的Token * @param expiration 持续时间 * @param identyinfo 备注信息,为jwt中间的数据部分 * @param token token值 * @param cutToken token对象类 * @param */ public void SaveTokenRecord(Long expiration,String identyinfo,String token,CustomerToken cutToken,String clientIp){ TokenRecord record=new TokenRecord(); record.setApplytime(new Date()); record.setExpiration(expiration!=null?expiration.intValue():expireSeconds.intValue()); record.setResourceid(Integer.valueOf(cutToken.getResourceId())); record.setIdentyinfo(identyinfo); record.setTokeninfo(cutToken.toString()); record.setToken(token); record.setTokenapplyer(clientIp); logMapper.saveTokenRecord(record); } /** * 外部调用 * 临时token获取 * @param resourceid 资源id * @param req * @param expiration 失效时间 * @param identyinfo 备注信息 表明 token使用人 * @param appUrl 申请token系统地址 * @param isPubzy 公开级别 * @param appId 应用id * @param applyuserid token申请人用户id * @return */ @RequestMapping(value = "/genTokenForApply", method = RequestMethod.GET) public @ResponseBody String genTokenForApply(String resourceid,HttpServletRequest req,Long expiration,String identyinfo,String appUrl,Boolean isPubzy,String appId,String applyuserid,String isNever ) { // 已经存在的token 直接返回token Map param = new HashMap<>(); param.put("resourceid", Integer.parseInt(resourceid)); param.put("userid", applyuserid); List maps = serverRegisterService.queryServer(param); if (CollectionUtil.isNotEmpty(maps)) { String tokenTemp = logservice.queryToken(param); JSONObject json = new JSONObject(); boolean tokenIsExtend = ZiyuanRightManager.CheckTokenIsExtend(tokenTemp); if (tokenIsExtend) { json.put("code", 200); json.put("data", tokenTemp); return json.toJSONString(); } String clientIp = req.getLocalAddr(); Jedis jedis = jedisUtils.getJedis(); try { CustomerToken cutToken = new CustomerToken(); cutToken.setResourceId(resourceid); cutToken.setUserid(applyuserid); cutToken.setAppUrl(appUrl); cutToken.setIsPubzy(isPubzy); cutToken.setAppId(appId); cutToken.setClientIp(req.getRemoteHost()); cutToken.setRemark(identyinfo); if (expiration == null) { expiration = expireSeconds * 30; } String token = expiration != null ? jwtUtils.generateToken(cutToken.toString(), expiration) : jwtUtils.generateToken(cutToken.toString(), expireSeconds); //默认给30天 SaveTokenRecord(expiration, identyinfo, token, cutToken, clientIp); if (StringUtils.equals(isNever, "1")) { jedis.set("zytoken:" + token, "1"); //永久有效 } else { jedis.setex("zytoken:" + token, expiration != null ? expiration.intValue() : expireSeconds.intValue(), "1"); } jedis.setex("zytoken:" + token, expiration != null ? expiration.intValue() : expireSeconds.intValue(), "1"); json.put("code", 200); json.put("data", token); json.put("message", "获取成功"); return json.toJSONString(); } catch (Exception e) { e.printStackTrace(); } finally { jedis.close(); } return "error"; } return "error"; } }