发表于: 2018-10-19 21:04:03
1 340
今天完成的事情
1.解决昨天的bug,直接加一个ip-address指定ip地址即可
2.学习翁涵大佬的权限模块
zuul网关配置
spring:
application:
name: appi-zuul
redis:
# Redis数据库索引(默认为0)
database: 0
# Redis服务器地址
host: 127.0.0.1
# Redis服务器连接端口
port: 6379
# Redis服务器连接密码(默认为空)
password:
jedis:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 20
# 连接池中的最大空闲连接
max-idle: 10
# 连接池中的最小空闲连接
min-idle: 5
server:
port: 5555
zuul:
routes:
rbac:
path: /a/rbac/**
serviceId: rbac-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:1111/eureka/
过滤逻辑:
package com.wh.demozull.accessfilter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.wh.demozull.utils.JwtUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.data.redis.core.RedisTemplate;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* @Author: 快乐水 樱桃可乐
* @Description:
* @Date: Created in 13:09 2018/9/30
* @Modified By:
*/
public class ReceptionFilter extends ZuulFilter {
private static final String key = "Happywater";
private static Logger logger = LoggerFactory.getLogger(BackstageFilter.class);
@Autowired
private RedisTemplate redisTemplate;
@Override
public String filterType() {
return FilterConstants.ROUTE_TYPE;
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request=context.getRequest();
//获取url的路径
String path=request.getRequestURI();
//对url进行分割
String[] uriList=path.split("/");
//如果是后台路径则放行
if("a".equals(uriList[1])){
return false;
}
//如果是不需要登录的路径则放行
if("o".equals(uriList[3])){
return false;
}
//其余的接口是:前台需要登录才能访问的接口,进入run过滤器
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext context=RequestContext.getCurrentContext();
HttpServletRequest request=context.getRequest();
//获取路径
String path=request.getRequestURI();
//分割路径
String[] uriList=path.split("/");
//获取请求头中的JWT
String jwt=request.getHeader("JWT");
logger.info("jwt: "+jwt);
//请求头中不存在JWT:未登录
if(jwt==null){
logger.info("无Token");
context.put(FilterConstants.REQUEST_URI_KEY,"/reception/notJwt");
return null;
}
//使用Map获取jwt中的值
Map map=JwtUtil.parseJWT(jwt,key);
//JWT验证:取jwt中的值与密钥重创jwt,对比验证
if(!JwtUtil.createJWT(map,key).equals(jwt)){
logger.info("JWT不可信");
context.put(FilterConstants.REQUEST_URI_KEY,"/reception/UntrustworthyJwt");
return null;
}
//从jwt中获取前台id:前台使用receptionId作为id的key
Integer id=(Integer)map.get("receptionId");
//通过前台id在redis从库中获取redisJwt
String redisJwt=(String) redisTemplate.opsForValue().get(id+"");
logger.info("redisJwt: "+redisJwt);
//如果redis中不存在对应的JWT,表明已注销
if(redisJwt==null){
logger.info("已注销,请重新登录");
context.put(FilterConstants.REQUEST_URI_KEY,"/reception/notCorrespondingJwt");
return null;
}
//用户的jwt与redis中的jwt不相同,则表明请求头中的jwt已失效
if(!jwt.equals(redisJwt)){
logger.info("jwt已过期");
context.put(FilterConstants.REQUEST_URI_KEY,"/reception/invalidJwt");
return null;
}
//其余情况放行
return null;
}
}
package com.wh.demozull.accessfilter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.wh.demozull.utils.JwtUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.data.redis.core.RedisTemplate;
import javax.jnlp.FileContents;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
/**
* @Author: 快乐水 樱桃可乐
* @Description:
* @Date: Created in 9:45 2018/9/29
* @Modified By:
*/
public class BackstageFilter extends ZuulFilter {
private static final String key = "Happywater";
private static Logger logger = LoggerFactory.getLogger(BackstageFilter.class);
@Autowired
private RedisTemplate redisTemplate;
@Override
public String filterType() {
//返回字符串代表过滤的类型,在zuul中定义了四种不同生命周期的过滤类型
//1.pre:路由之前,FilterConstants.PRE_TYPE;
//2.routing:路由之时,FilterConstants.ROUTE_TYPE;
//3.post:路由之后,FilterConstants.POST_TYPE;
//4.error:发送错误调用,FilterConstants.ERROR_TYPE;
return FilterConstants.ROUTE_TYPE;
}
@Override
public int filterOrder() {
//过滤的顺序
return 0;
}
@Override
public boolean shouldFilter() {
//写逻辑判断,是否要过滤,如果为True则过滤
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request=context.getRequest();
//获取url的路径
String path=request.getRequestURI();
String[] uriList=path.split("/");
//如果是前台路径直接放行
if("u".equals(uriList[1])){
return false;
}
//如果是后台登录的路径则直接放行
if("login".equals(uriList[3])){
return false;
}
//如果是后台接口(除后台登陆外),则进入拦截器
return true;
}
@Override
public Object run() throws ZuulException {
//过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问
RequestContext context=RequestContext.getCurrentContext();
HttpServletRequest request=context.getRequest();
//获取请求路径
String path=request.getRequestURI();
//分割路径,获取uri
String[] uriList=path.split("/");
//从Header中获取jwt
String jwt=request.getHeader("JWT");
logger.info("jwt: "+jwt);
//请求头中不存在JWT
if(jwt==null){
logger.info("无Token");
context.put(FilterConstants.REQUEST_URI_KEY,"/backstage/notJwt");
return null;
}
//解密JWT,保存到map对象中
Map map=JwtUtil.parseJWT(jwt,key);
//JWT验证:取jwt中的值与密钥重创jwt,对比验证
if(!JwtUtil.createJWT(map,key).equals(jwt)){
//不对应表示:请求头中的JWT不可信
logger.info("JWT不可信");
context.put(FilterConstants.REQUEST_URI_KEY,"/backstage/UntrustworthyJwt");
return null;
}
//获取后台JWT中的ID
Integer id=(Integer)map.get("backstageId");
logger.info("当前操作者的id: "+id);
//从redis中获取对应ID的JWT
String redisJwt=(String) redisTemplate.opsForValue().get("backstageId"+id+"");
logger.info("redisJwt: "+redisJwt);
//redis中无对应的jwt表明,已注销
if(redisJwt==null){
logger.info("已注销,请重新登录");
context.put(FilterConstants.REQUEST_URI_KEY,"/backstage/notCorrespondingJwt");
return null;
}
//用户的jwt与redis中的jwt不相同,表明请求头中的JWT已失效,通过此步代表登录成功
if(!jwt.equals(redisJwt)){
logger.info("jwt已过期");
context.put(FilterConstants.REQUEST_URI_KEY,"/backstage/invalidJwt");
return null;
}
//如果是注销操作或获取左边栏操作则直接放行(不需要权限验证)
if("logout".equals(uriList[3])||"modules".equals(uriList[3])){
return null;
}
//获取权限URI
int size=uriList.length;
String permission;
//判断最后一个url是否为纯数字
if(StringUtils.isNumeric(uriList[size-1])){
permission=uriList[size-3];
}else{
permission=uriList[size-2];
}
logger.info("访问该接口需要的权限: "+permission);
//获取当前账户jwt中的权限集合
List<String> authority= (List) map.get("authority");
logger.info("用户具有的权限数量为: "+authority.size());
//遍历权限,查看是否存在接口所需的权限
if(authority.size()!=0) {
for (String s : authority) {
logger.info("用户具有的权限: " + s);
if (s.equals(permission)) {
logger.info("具有权限");
//如果有匹配的权限,放行
return null;
}
}
}
//设置没需要的权限,要跳转的路径
context.put(FilterConstants.REQUEST_URI_KEY,"/backstage/notAuthority");
return null;
}
}
JWT的工具类的编写
package com.wh.demozull.utils;
import com.google.gson.Gson;
import com.wh.demozull.accessfilter.BackstageFilter;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: 快乐水 樱桃可乐
* @Description:
* @Date: Created in 18:06 2018/9/28
* @Modified By:
*/
public class JwtUtil {
private static Logger logger = LoggerFactory.getLogger(BackstageFilter.class);
/**
* 解密
* @param jsonWebToken
* @param base64Security
* @return
*/
public static Claims parseJWT(String jsonWebToken, String base64Security) {
try {
Claims claims = Jwts.parser()
.setSigningKey(base64Security.getBytes())
.parseClaimsJws(jsonWebToken).getBody();
return claims;
} catch (Exception ex) {
logger.info("解密异常");
return null;
}
}
/**
* 前三个参数为自己用户token的一些信息比如id,权限,名称等。不要将隐私信息放入(大家都可以获取到)
* @param map
* @param base64Security
* @return
*/
public static String createJWT(Map<String, Object> map, String base64Security) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
//添加构成JWT的参数
JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
.setPayload(new Gson().toJson(map))
//估计是第三段密钥
.signWith(signatureAlgorithm,base64Security.getBytes());
//生成JWT
return builder.compact();
}
public static void main(String[] args) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("province", "898765");
map.put("city", "898765");
map.put("appkey", "HMu1H/cmyKDOiHv41Y9lLROuOlOo+PPG8F4/RotRmNc=");
map.put("timestamp", System.currentTimeMillis());
//密钥
String keyt = "Happywater";
String token=JwtUtil.createJWT(map, keyt);
System.out.println("JWT加密的结果:"+ token);
System.out.println("JWT解密的结果:"+ parseJWT(token, keyt));
Map map1=parseJWT(token,keyt);
System.out.println(map1.get("city"));
}
}
还有其他的还没看,明天再捋一捋
明天计划的事情
继续看权限模块的东西
遇到的问题
如上
收获
如上
评论