netty tcp(WebSocket)鉴权2个方案
1
本方案基于netty channel的线程安全性与@Sharable中结论,pipeline线程安全
增加一个AuthHandler,顶在pipeline最前面
鉴权不通过,close channel,通过,remove掉这个鉴权channelhandler
取自jds-im,msgforwarder AuthWsHandler
------------------------------------------------------------------------------------------------
* ctx.pipeline().remove(this);
1.5
no remove AuthHandler
channel.attribute.get
null - 是否鉴权请求
否 close
是 鉴权
not null 直接放行ctx.fireChannelRead
2
connect时鉴权,将信息放在ws url中
前端:ws = new WebSocket(WS_URL + ";" + getCookie('token'));
服务端在握手前:
public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest> { private static final Logger logger = LoggerFactory.getLogger(HttpRequestHandler.class); public static AttributeKey<String> TOKEN = AttributeKey.valueOf("token"); public static AttributeKey<String> USERNAME = AttributeKey.valueOf("userName"); @Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { String url = request.getUri(); if(-1 != url.indexOf("/ws")) { String temp [] = url.split(";"); if(temp.length >= 2) { String token = URLDecoder.decode(temp[1], "UTF-8"); ctx.channel().attr(TOKEN).set(token); } request.setUri("/ws"); // 传递到下一个handler:升级握手 ctx.fireChannelRead(request.retain()); } else { logger.error("not socket"); ctx.close(); } }
握手后:
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) { // 移除性能更加 ctx.pipeline().remove(HttpRequestHandler.class); boolean hasAuth = false; String userName = null; String token = ctx.channel().attr(HttpRequestHandler.TOKEN).get(); if(token == null || "".equals(token)) { logger.warn("no token"); } else { userName = GlobalContext.channelUser.get(token); if(userName != null && !"".equals(userName)) { ctx.channel().attr(HttpRequestHandler.USERNAME).set(userName); hasAuth = true; } else { logger.warn("no user"); } } if(hasAuth) { String up = userName + "[connected]"; logger.info(up); // for(int i=0; i<100; ++i) ctx.writeAndFlush(up); group.add(ctx.channel()); } else { String noToken = "[您的token非法,请重新登录]"; logger.warn(noToken); ctx.writeAndFlush(noToken).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) throws Exception { channelFuture.channel().close(); } }); }
实践具体位置参见:https://www.cnblogs.com/silyvin/articles/9590595.html