一、报文封装类

AbstractPortalMsg.java
Portal协议数据报文封装类
 package org.yoki.edu.common.protocol.portal.msg;

 import lombok.Data;
import lombok.ToString;
import org.yoki.edu.common.protocol.portal.msg.attr.MsgAttr; import java.util.ArrayList;
import java.util.List; /**
* Portal协议数据报文封装类
*
* @author Sky$
* @Description: TODO
* @date 2017/10/24$ 19:16$
*/
@Data
@ToString
public abstract class AbstractPortalMsg { protected int ver;
protected int type;
protected int papChap = 1;
protected int rsvd = 0;
protected int serialNo;
protected int reqId;
protected String userIp;
protected int userPort = 0;
protected int errCode;
protected int attrNum;
/**
* 属性列表
*/
protected List<MsgAttr> attrList = new ArrayList<>(); /**
* 添加属性的方法
*
* @param attr
* @return
*/
public List<MsgAttr> addMsgAttr(MsgAttr attr) {
if (null == attrList) {
attrList = new ArrayList<>();
}
attrList.add(attr);
return attrList;
} /**
* 将hander部分的字段转化为16个字节
*
* @return
*/
protected byte[] getHander16Bytes() {
byte[] b = new byte[16];
b[0] = (byte) (ver & 0xff);
b[1] = (byte) (type & 0xff);
b[2] = (byte) (papChap & 0xff);
b[3] = (byte) (rsvd & 0xff);
b[4] = (byte) (serialNo >> 8 & 0xff);
b[5] = (byte) (serialNo & 0xff);
b[6] = (byte) (reqId >> 8 & 0xff);
b[7] = (byte) (reqId & 0xff);
byte[] ip = ipv4Address2BinaryArray(userIp);
System.arraycopy(ip, 0, b, 8, 4);
b[12] = (byte) (userPort >> 8 & 0xff);
b[13] = (byte) (userPort & 0xff);
b[14] = (byte) (errCode & 0xff);
b[15] = (byte) (attrNum & 0xff);
return b;
} /**
* 将属性列表转化为字节数组
*
* @return
*/
protected byte[] getAttrBytes() {
int attrByteNum = 0;
if (attrList != null && !attrList.isEmpty()) {
for (MsgAttr a : attrList) {
attrByteNum += a.getAttrLen();
}
}
byte[] b = new byte[attrByteNum];
int index = 0;
if (attrList != null && !attrList.isEmpty()) {
for (MsgAttr a : attrList) {
System.arraycopy(a.getByteValues(), 0, b, index, a.getByteValues().length);
index += a.getByteValues().length;
}
}
return b;
} /**
* 抽象方法:获取该报文类的字节数组<br>
* 抽象出该方法是因为移动Portal和华为Portal协议有些区别<br>
* 华为Portal有一个MD5加密字段
*
* @return
*/
public abstract byte[] toByteArray(); /**
* 抽象方法:通过报文字节数组,解析出各个字段值,并赋值<br>
* 抽象出该方法是因为移动Portal和华为Portal协议有些区别<br>
* 华为Portal有一个MD5加密字段
*
* @param input Portal协议报文字节数组
*/
public abstract void parse(byte[] input); /**
* 通过报文字节数组,解析出header部分的信息,并赋值
*
* @param input Portal协议报文字节数组
*/
protected void parseHeader(byte[] input) {
this.setVer(input[0]);
this.setType(input[1]);
this.setPapChap(input[2]);
this.setRsvd(input[3]); this.setSerialNo(((0xff & input[4]) << 8) | (0xff & input[5]));
this.setReqId(((0xff & input[6]) << 8) | (0xff & input[7])); this.setUserIp((input[8] & 0xff) + "." + (input[9] & 0xff) + "." + (input[10] & 0xff) + "." + (input[11] & 0xff));
this.setUserPort(((0xff & input[12]) << 8) | (0xff & input[13])); this.setErrCode(0xff & input[14]);
this.setAttrNum(0xff & input[15]);
} /**
* 通过报文字节数组,解析出attr部分的信息,并赋值
*
* @param attrBytes attr数组的字节数组
* @param attrNum attr的个数
*/
protected void parseAttr(byte[] attrBytes, int attrNum) {
List<MsgAttr> attrList = new ArrayList<MsgAttr>();
int count = attrNum;
if (count > 0) {
int t = 0;
for (int i = 0; i < count; i++) {
int attrType = attrBytes[t];
int attrLen = attrBytes[t + 1];
byte[] d = new byte[attrLen - 2];
System.arraycopy(attrBytes, t + 2, d, 0, attrLen - 2);
MsgAttr c = new MsgAttr(attrType, new String(d));
attrList.add(c);
t += c.getAttrLen();
}
}
this.setAttrList(attrList);
} /**
* IP地址转换工具方法,将IP字符串转换为字节数组
*
* @param ipAdd
* @return
*/
protected byte[] ipv4Address2BinaryArray(String ipAdd) {
byte[] binIP = new byte[4];
String[] strs = ipAdd.split("\\.");
for (int i = 0; i < strs.length; i++) {
binIP[i] = (byte) Integer.parseInt(strs[i]);
}
return binIP;
} }

PortalV1Msg.java
移动Portal协议数据报文封装类
 package org.yoki.edu.common.protocol.portal.msg;

 import lombok.NoArgsConstructor;
import org.yoki.edu.common.protocol.portal.msg.attr.MsgAttr; import java.util.List; /**
* 移动Portal协议数据报文封装类
*
* @author Sky$
* @Description: TODO
* @date 2017/10/25$ 14:52$
*/
@NoArgsConstructor
public class PortalV1Msg extends AbstractPortalMsg { public PortalV1Msg(int ver, int type, int serialNo, int reqId, String userIp, int errCode, int attrNum, List<MsgAttr> attr) {
super();
this.ver = ver;
this.type = type;
this.serialNo = serialNo;
this.reqId = reqId;
this.userIp = userIp;
this.errCode = errCode;
this.attrNum = attrNum;
this.attrList = attr;
} public PortalV1Msg(int ver, int type, int papChap, int rsvd, int serialNo, int reqId, String userIp, int userPort,
int errCode, int attrNum, List<MsgAttr> attr) {
super();
this.ver = ver;
this.type = type;
this.papChap = papChap;
this.rsvd = rsvd;
this.serialNo = serialNo;
this.reqId = reqId;
this.userIp = userIp;
this.userPort = userPort;
this.errCode = errCode;
this.attrNum = attrNum;
this.attrList = attr;
} @Override
public byte[] toByteArray() {
byte[] headerBytes = getHander16Bytes();
byte[] attrBytes = getAttrBytes();
byte[] b = new byte[headerBytes.length + attrBytes.length];
if (null != headerBytes && headerBytes.length > 0) {
System.arraycopy(headerBytes, 0, b, 0, headerBytes.length);
}
b[15] = (byte) this.attrList.size();
if (null != attrBytes && attrBytes.length > 0) {
System.arraycopy(attrBytes, 0, b, 16, attrBytes.length);
}
return b;
} @Override
public void parse(byte[] input) { if (null != input && input.length >= 16) {
byte[] headerBytes = new byte[16];
System.arraycopy(input, 0, headerBytes, 0, headerBytes.length);
this.parseHeader(headerBytes); int attrNum = input[15];
byte[] attrBytes = new byte[input.length - 16];
System.arraycopy(input, 16, attrBytes, 0, attrBytes.length);
parseAttr(attrBytes, attrNum);
} } }
MsgAttr.java
Portal数据报文Attr字段封装父类
 package org.yoki.edu.common.protocol.portal.msg.attr;

 import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor; import java.util.Arrays; /**
* Portal数据报文Attr字段封装父类
*
* @author Sky$
* @Description: TODO
* @date 2017/10/24$ 20:44$
*/
@Data
public class MsgAttr { private int attrType;
private int attrLen;
private String attrValue;
private byte[] byteValues; protected MsgAttr() { } public MsgAttr(int attrType, String attrValue) {
this.attrType = attrType;
this.attrLen = 2 + attrValue.getBytes().length;
this.attrValue = attrValue; byteValues = new byte[attrLen];
byteValues[0] = (byte) attrType;
byteValues[1] = (byte) attrLen;
System.arraycopy(attrValue.getBytes(), 0, byteValues, 2, attrValue.getBytes().length);
} }

UserNameMsgAttr.java
 package org.yoki.edu.common.protocol.portal.msg.attr;

 /**
* @author Sky$
* @Description: TODO
* @date 2017/10/29$ 15:05$
*/
public class UserNameMsgAttr extends MsgAttr { public UserNameMsgAttr(String userName){
super(0x01 , userName) ;
} }
PasswordMsgAttr.java
 package org.yoki.edu.common.protocol.portal.msg.attr;

 /**
* @author Sky$
* @Description: TODO
* @date 2017/10/29$ 15:08$
*/
public class PasswordMsgAttr extends MsgAttr { public PasswordMsgAttr(String password){
super(0x02 , password) ;
} }

ChallengeMsgAttr.java
 package org.yoki.edu.common.protocol.portal.msg.attr;

 /**
* @author Sky$
* @Description: TODO
* @date 2017/10/29$ 15:09$
*/
public class ChallengeMsgAttr extends MsgAttr { public ChallengeMsgAttr(String challenge){
super(0x03 , challenge) ;
} }
ChapPasswordMsgAttr.java
 package org.yoki.edu.common.protocol.portal.msg.attr;

 /**
* @author Sky$
* @Description: TODO
* @date 2017/10/29$ 15:09$
*/
public class ChapPasswordMsgAttr extends MsgAttr { public ChapPasswordMsgAttr(String chapPassword){
super(0x04 , chapPassword) ;
} }

二、工具类
ChapEncryptUtils.java
Chap加密工具类
 package org.yoki.edu.common.protocol.portal.utils;

 import org.yoki.edu.common.utils.encrypt.EncryptUtils;

 /**
* Chap加密
*
* @author Sky$
* @Description: TODO
* @date 2017/10/27$ 17:20$
*/
public class ChapEncryptUtils { public static byte[] encryptChap(int reqId, String challenge, String pwd) {
byte[] chapPwd = encryptChap(reqId, challenge.getBytes(), pwd.getBytes());
return chapPwd;
} public static byte[] encryptChap(int reqId, byte[] challenge, byte[] pwd) {
/**
* Chap_Password(Chap密码)的生成:
* Chap_Password的生成遵循标准的Radious协议中的Chap_Password 生成方法(参见RFC2865)。
* 密码加密使用MD5算法,MD5函数的输入为ChapID + Password +Challenge (reqId有AC生成, ChapID是ReqID的低8位)
* 其中,ChapID取reqId的低 8 位,Password的长度不够协议规定的最大长度,其后不需要补零。
* Chap_Password = MD5 (ChapID+ Password + Challenge )
*/
byte[] buf = new byte[1 + pwd.length + challenge.length];
buf[0] = (byte) (reqId & 0xff);
System.arraycopy(pwd, 0, buf, 1, pwd.length);
System.arraycopy(challenge, 0, buf, 1 + pwd.length, challenge.length);
byte[] chapPwd = EncryptUtils.encryptMD5Bytes(buf);
return chapPwd;
} }

三、Portal协议工具类
PortalV1ChapMsgBuilder.java
CHAP方式Portal报文生产工具类
 package org.yoki.edu.common.protocol.portal.v1.builder;

 import org.yoki.edu.common.protocol.portal.msg.attr.UserNameMsgAttr;
import org.yoki.edu.common.protocol.portal.utils.ChapEncryptUtils;
import org.yoki.edu.common.protocol.portal.msg.PortalV1Msg;
import org.yoki.edu.common.protocol.portal.msg.attr.ChapPasswordMsgAttr; /**
* CHAP方式Portal报文生产工具类
*
* @author Sky$
* @Description: TODO
* @date 2017/10/29$ 14:37$
*/
public class PortalV1ChapMsgBuilder { /**
* 生成Chanllenge请求报文
*
* @param serialNo
* @param userIp 用户IP
* @return
*/
public PortalV1Msg buildReqChallengeMsg(int serialNo, String userIp) {
PortalV1Msg msg = buildV1ChapMsg();
msg.setType(1);
msg.setReqId(0);
msg.setSerialNo(serialNo);
msg.setUserIp(userIp);
msg.setAttrNum(0);
return msg;
} /**
* 生成认证请求报文
*
* @param reqId
* @param serialNo
* @param userIp
* @param userName
* @param password
* @param challenge
* @return
*/
public PortalV1Msg buildReqAuthMsg(int reqId, int serialNo, String userIp, String userName, String password, String challenge) {
PortalV1Msg msg = buildV1ChapMsg();
msg.setType(3);
msg.setSerialNo(serialNo);
msg.setReqId(reqId);
msg.setUserIp(userIp);
msg.setAttrNum(2);
UserNameMsgAttr userNameMsgAttr = new UserNameMsgAttr(userName);
byte[] chapPassworldBytes = ChapEncryptUtils.encryptChap(reqId, challenge, password);
ChapPasswordMsgAttr chapPasswordMsgAttr = new ChapPasswordMsgAttr(new String(chapPassworldBytes));
msg.addMsgAttr(userNameMsgAttr).add(chapPasswordMsgAttr);
return msg;
} /**
* 生成下线请求报文
*
* @param reqId
* @param serialNo
* @param userIp
* @return
*/
public PortalV1Msg buildReqLogoutMsg(int reqId, int serialNo, String userIp) {
PortalV1Msg msg = buildV1ChapMsg();
msg.setType(5);
msg.setSerialNo(serialNo);
msg.setReqId(reqId);
msg.setUserIp(userIp);
msg.setAttrNum(0);
return msg;
} /**
* 生成认证接收响应报文
*
* @param reqId
* @param serialNo
* @param userIp
* @return
*/
public PortalV1Msg buildAffAckAuthMsg(int reqId, int serialNo, String userIp) {
PortalV1Msg msg = buildV1ChapMsg();
msg.setType(7);
msg.setSerialNo(serialNo);
msg.setReqId(reqId);
msg.setUserIp(userIp);
msg.setAttrNum(0);
return msg;
} private PortalV1Msg buildV1ChapMsg() {
PortalV1Msg msg = new PortalV1Msg();
msg.setVer(1); msg.setPapChap(0);
msg.setRsvd(0); msg.setUserPort(0);
msg.setErrCode(0);
return msg;
} }


PortalV1PapMsgBuilder.java
PAP方式Portal报文生产工具类
 package org.yoki.edu.common.protocol.portal.v1.builder;

 import org.yoki.edu.common.protocol.portal.msg.PortalV1Msg;
import org.yoki.edu.common.protocol.portal.msg.attr.PasswordMsgAttr;
import org.yoki.edu.common.protocol.portal.msg.attr.UserNameMsgAttr; /**
* PAP方式Portal报文生产工具类
*
* @author Sky$
* @Description: TODO
* @date 2017/10/29$ 14:37$
*/
public class PortalV1PapMsgBuilder { /**
* 生成认证请求报文
*
* @param serialNo
* @param userIp
* @param userName
* @param password
* @return
*/
public PortalV1Msg buildReqAuthMsg(int serialNo, String userIp, String userName, String password) {
PortalV1Msg msg = buildV1PapMsg();
msg.setType(3);
msg.setSerialNo(serialNo); msg.setUserIp(userIp);
msg.setAttrNum(2);
UserNameMsgAttr userNameMsgAttr = new UserNameMsgAttr(userName);
PasswordMsgAttr passwordMsgAttr = new PasswordMsgAttr(password);
msg.addMsgAttr(userNameMsgAttr).add(passwordMsgAttr);
return msg;
} /**
* 生成下线请求报文
*
* @param serialNo
* @param userIp
* @return
*/
public PortalV1Msg buildReqLogoutMsg(int serialNo, String userIp) {
PortalV1Msg msg = buildV1PapMsg();
msg.setType(5);
msg.setSerialNo(serialNo);
msg.setUserIp(userIp);
msg.setAttrNum(0);
return msg;
} /**
* 生成认证接收响应报文
*
* @param serialNo
* @param userIp
* @return
*/
public PortalV1Msg buildAffAckAuthMsg(int serialNo, String userIp) {
PortalV1Msg msg = buildV1PapMsg();
msg.setType(7);
msg.setSerialNo(serialNo);
msg.setUserIp(userIp);
msg.setAttrNum(0);
return msg;
} private PortalV1Msg buildV1PapMsg() {
PortalV1Msg msg = new PortalV1Msg();
msg.setVer(1); msg.setPapChap(1);
msg.setRsvd(0); msg.setReqId(0); msg.setUserPort(0);
msg.setErrCode(0);
return msg;
} }

PortalV1MsgParser.java
报文解析工具类
 package org.yoki.edu.common.protocol.portal.v1.parser;

 import org.yoki.edu.common.protocol.portal.exception.PortalException;
import org.yoki.edu.common.protocol.portal.exception.enums.PortalErrorStatusEnum;
import org.yoki.edu.common.protocol.portal.msg.PortalV1Msg; /**
* 报文解析工具类
*
* @author Sky$
* @Description: TODO
* @date 2017/10/29$ 15:59$
*/
public class PortalV1MsgParser { private final int ACK_CHALLENGE = 0X02;
private final int ACK_AUTH = 0X04;
private final int ACK_LOGOUT = 0X06; private final int ERROR_CODE_1 = 1;
private final int ERROR_CODE_2 = 2;
private final int ERROR_CODE_3 = 3;
private final int ERROR_CODE_4 = 4; public PortalV1Msg parse(byte[] input) throws PortalException {
PortalV1Msg msg = new PortalV1Msg();
msg.parse(input);
parse(msg);
return msg;
} public void parse(PortalV1Msg msg) throws PortalException {
Integer type = msg.getType();
Integer errorCode = msg.getErrCode();
PortalErrorStatusEnum[] enums = PortalErrorStatusEnum.values();
for (PortalErrorStatusEnum e : enums) {
if (e.getErrCode() == errorCode && e.getType() == type) {
throw new PortalException(e);
}
}
} }
PortalV1PapMsgSender.java
Portal报文发送工具类
内部调用DatagramSocket进行UDP报文发送
 package org.yoki.edu.common.protocol.portal.v1.sender;

 import lombok.Getter;
import lombok.Setter;
import org.yoki.edu.common.protocol.portal.v1.builder.PortalV1PapMsgBuilder;
import org.yoki.edu.common.protocol.portal.exception.PortalException;
import org.yoki.edu.common.protocol.portal.msg.PortalV1Msg;
import org.yoki.edu.common.protocol.portal.v1.parser.PortalV1MsgParser; import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress; /**
* Portal报文发送工具类<br>
* 内部调用DatagramSocket进行UDP报文发送
*
* @author Sky$
* @Description: TODO
* @date 2017/10/31$ 17:57$
*/
public class PortalV1PapMsgSender { @Setter
@Getter
private int timeOut = 5000; @Setter
@Getter
private Integer receiverPort = null; /**
* REQ_AUTH 0x03 Client----->Server AbstractPortalMsg Server向AC设备发送的请求认证报文
*
* @param serialNo
* @param loginIp
* @param loginName
* @param password
* @param acIp
* @param acPort
* @return
* @throws Exception
*/
public byte[] sendReqAuth(int serialNo, String loginIp, String loginName, String password, String acIp, int acPort) throws IOException {
DatagramSocket dataSocket = null;
byte[] ackData = new byte[0];
dataSocket = null;
DatagramPacket requestPacket = null;
PortalV1PapMsgBuilder builder = new PortalV1PapMsgBuilder();
PortalV1Msg msg = builder.buildReqAuthMsg(serialNo, loginIp, loginName, password);
byte[] msgBytes = msg.toByteArray();
// 创建连接
if (null != receiverPort) {
dataSocket = new DatagramSocket(receiverPort);
} else {
dataSocket = new DatagramSocket();
}
// 创建发送数据包并发送给服务器
requestPacket = new DatagramPacket(msgBytes, msgBytes.length, InetAddress.getByName(acIp), acPort);
ackData = new byte[1024];
// 接收服务器的数据包
DatagramPacket receivePacket = new DatagramPacket(ackData, 32);
// 设置请求超时3秒
dataSocket.setSoTimeout(timeOut);
dataSocket.send(requestPacket);
dataSocket.receive(receivePacket); if (null != dataSocket) {
dataSocket.disconnect();
dataSocket.close();
}
return ackData; } /**
* REQ_AUTH 0x03 Client----->Server AbstractPortalMsg Server向AC设备发送的请求认证报文
*
* @param serialNo
* @param loginIp
* @param loginName
* @param password
* @param acIp
* @param acPort
* @return
* @throws Exception
*/
public PortalV1Msg sendAndParseReqAuth(int serialNo, String loginIp, String loginName, String password, String acIp, int acPort) throws PortalException, IOException {
byte[] ackData = sendReqAuth(serialNo, loginIp, loginName, password, acIp, acPort);
PortalV1MsgParser msgParser = new PortalV1MsgParser();
PortalV1Msg reciveMsg = msgParser.parse(ackData);
reciveMsg.parse(ackData);
return reciveMsg; } /**
* AbstractPortalMsg Server对收到的认证成功响应报文的确认报文;
*
* @param serialNo
* @param loginIp
* @param acIp
* @param acPort
* @throws Exception
*/
public void sendAffAckAuth(int serialNo, String loginIp, String acIp, int acPort) throws IOException {
DatagramSocket dataSocket = null;
PortalV1PapMsgBuilder builder = new PortalV1PapMsgBuilder();
PortalV1Msg msg = builder.buildAffAckAuthMsg(serialNo, loginIp);
byte[] msgBytes = msg.toByteArray();
// 创建连接
if (null != receiverPort) {
dataSocket = new DatagramSocket(receiverPort);
} else {
dataSocket = new DatagramSocket();
}
// 创建发送数据包并发送给服务器
DatagramPacket requestPacket = new DatagramPacket(msgBytes, msgBytes.length, InetAddress.getByName(acIp), acPort);
// 接收服务器的数据包
dataSocket.send(requestPacket);
if (null != dataSocket) {
dataSocket.disconnect();
dataSocket.close();
}
} /**
* AbstractPortalMsg Server向AC设备发送的请求用户下线报文
*
* @param serialNo
* @param loginIp
* @param acIp
* @param acPort
* @return
* @throws Exception
*/
public byte[] sendReqLogout(int serialNo, String loginIp, String acIp, int acPort) throws IOException {
DatagramSocket dataSocket = null;
byte[] ackData = new byte[0];
PortalV1PapMsgBuilder builder = new PortalV1PapMsgBuilder();
PortalV1Msg msg = builder.buildReqLogoutMsg(serialNo, loginIp);
byte[] msgBytes = msg.toByteArray();
// 创建连接
if (null != receiverPort) {
dataSocket = new DatagramSocket(receiverPort);
} else {
dataSocket = new DatagramSocket();
}
// 创建发送数据包并发送给服务器
DatagramPacket requestPacket = new DatagramPacket(msgBytes, msgBytes.length, InetAddress.getByName(acIp), acPort);
ackData = new byte[1024];
// 接收服务器的数据包
DatagramPacket receivePacket = new DatagramPacket(ackData, 32);
// 设置请求超时3秒
dataSocket.setSoTimeout(timeOut);
dataSocket.send(requestPacket);
dataSocket.receive(receivePacket);
if (null != dataSocket) {
dataSocket.disconnect();
dataSocket.close();
}
return ackData; } /**
* AbstractPortalMsg Server向AC设备发送的请求用户下线报文
*
* @param serialNo
* @param loginIp
* @param acIp
* @param acPort
* @return
* @throws Exception
*/
public PortalV1Msg sendAndParseReqLogout(int serialNo, String loginIp, String acIp, int acPort) throws IOException, PortalException {
byte[] ackData = sendReqLogout(serialNo, loginIp, acIp, acPort);
PortalV1MsgParser msgParser = new PortalV1MsgParser();
PortalV1Msg reciveMsg = msgParser.parse(ackData);
reciveMsg.parse(ackData);
return reciveMsg; } }

四、使用示例

 
 /**
* 用户短信认证
*
* @param vo
* @return
*/
@RequestMapping(value = "userAuth", method = RequestMethod.POST)
public InvokeResult userAuth(MobileAuthReqVo vo) {
InvokeResult invokeResult = null;
if (null == vo || CommonUtils.isEmpty(vo.getLoginname(), vo.getPassword())) {
invokeResult = InvokeResult.failure("请填写手机号和验证码!");
} else if (!CommonUtils.isChinaPhoneLegal(vo.getLoginname())) {
invokeResult = InvokeResult.failure("手机号格式有误!");
} else {
//用户登陆IP
String loginIp = vo.getUserpriip();
int serialNo = (int) (65535 * Math.random());
PortalV1PapMsgSender sender = new PortalV1PapMsgSender();
sender.setTimeOut(60000);
try {
PortalV1Msg reciveMsg = sender.sendAndParseReqAuth(serialNo, loginIp, vo.getLoginname(), vo.getPassword(), acIp, acPort);
sender.sendAffAckAuth(serialNo, loginIp, acIp, acPort);
//重置密码,防止密码可以多次使用
Radcheck radcheck = new Radcheck() ;
radcheck.setUsername(vo.getLoginname());
radcheck.setLoginIp(loginIp);
radcheck.setDeviceMac(vo.getDeviceMac());
radcheck.updateIpAndMac();
invokeResult = InvokeResult.ok();
} catch (BizException e) {
e.printStackTrace();
invokeResult = InvokeResult.failure(e.getMessage());
} catch (Exception e) {
e.printStackTrace();
invokeResult = InvokeResult.error();
} }
return invokeResult;
}


wifi认证Portal开发系列(四):portal协议的java封装的更多相关文章

  1. S5PV210开发系列四_uCGUI的移植

    S5PV210开发系列四 uCGUI的移植 象棋小子          1048272975 GUI(图形用户界面)极大地方便了非专业用户的使用,用户无需记忆大量的命令,取而代之的是能够通过窗体.菜单 ...

  2. 转:arcgis api for js入门开发系列四地图查询

    原文地址:arcgis api for js入门开发系列四地图查询 arcgis for js的地图查询方式,一般来说,总共有三种查询方式:FindTask.IdentifyTask.QueryTas ...

  3. wifi认证Portal开发系列(三):portal协议

    中国移动WLAN业务PORTAL协议规范介绍 一.用户上线认证流程 上线流程完成用户账号的认证,并把认证结果通知Portal Server,Portal server将会通知WLAN用户并且显示相应的 ...

  4. 【Qt编程】基于Qt的词典开发系列<四>--无边框窗口的缩放与拖动

    在现在,绝大多数软件都向着简洁,时尚发展.就拿有道的单词本和我做的单词本来说,绝大多数用户肯定喜欢我所做的单词本(就单单界面,关于颜色搭配和布局问题,大家就不要在意了). 有道的单词本: 我所做的单词 ...

  5. BizTalk 开发系列(四十一) BizTalk 2010 BAM 安装手记

    使用64位系统可以支持更大的内存,现在服务器基本上都使用64位系统.微软从Windows Server 2008 R2开始服务器版的操作系统也只支持64位了,不过对于像BizTalk这种“繁杂的东西” ...

  6. 微信小程序开发系列四:微信小程序之控制器的初始化逻辑

    微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 微信小程序开发系列三:微信小程序的调试方法 这个教程的前两篇文章,介绍了如何 ...

  7. leaflet-webpack 入门开发系列四图层控件样式优化篇(附源码下载)

    前言 leaflet-webpack 入门开发系列环境知识点了解: node 安装包下载webpack 打包管理工具需要依赖 node 环境,所以 node 安装包必须安装,上面链接是官网下载地址 w ...

  8. wifi认证Portal开发系列(二):FreeRadius的安装和测试、关联Mysql

    注:本次安装是基于FreeRadius 3版本进行安装配置的,在配置Mysql的过程中,与2版本有些不同.操作系统是CentOS 7 一.准备工作 工具的安装 #安装rz.sz命令用于文件上传 yum ...

  9. wifi认证Portal开发系列(一):Radius与FreeRadius简介

    RADIUS 维基百科上的介绍: Remote Authentication Dial-In User Service (RADIUS) is a networking protocol that p ...

随机推荐

  1. 怎样让enum枚举支持string

    原文发布时间为:2011-03-02 -- 来源于本人的百度文章 [由搬家工具导入] 大家都知道enum是以下两种情况,不能支持string 1,enum类型是静态 2,enum类型仅限于long、i ...

  2. 呵呵呵呵。。。系统还原了,终于可以用IE登陆百度了

    原文发布时间为:2009-12-19 -- 来源于本人的百度文章 [由搬家工具导入] 呵呵呵呵。。。今天终于有时间把系统还原了,终于可以用IE登陆百度了

  3. 牛客挑战赛14-F细胞

    https://www.nowcoder.com/acm/contest/81/F 循环卷积的裸题,太久没做FFT了,这么裸的循环卷积都看不出来 注意一下本文的mod 都是指表示幂的模数,而不是NTT ...

  4. jmeter登录测试

    测试步骤: 1.测试计划--右键添加--Threads--线程组 2. 线程组--右键--http信息头管理器 输入Content-Type=application/json,表示接口请求的默认设置: ...

  5. [MySQL] Group Commit理解

    简单的方法理解MySQL Group Commit原理 一个摆渡将乘客从A点传输到B点 MySQL 5.0 行为 在MySQL 5.0中,摆渡会在A点按顺序搭载乘客,并且传送到B点.A点和B点的来回行 ...

  6. 学习环境配置:Manjaro、MSYS2以及常见软件

    0.前言 在说Manjaro之前,要先说一下Linux发行版.对于各大发行版而言,内核只有版本的差异,最重要的区别就是包管理系统.常见的包管理系统包括:Pacman,Apt , Yum和Portage ...

  7. map、hash_map、unordered_map 的思考

    #include <map> map<string,int> dict; map是基于红黑树实现的,可以快速查找一个元素是否存在,是关系型容器,能够表达两个数据之间的映射关系. ...

  8. DB2数据库报 [SQL0805N Package "NULLID.SQLLD003" was not found.]

    解决办法: cd /home/db2inst1/sqllib/bnddb2 bind @db2cli.lst blocking all grant public sqlerror continue C ...

  9. WebApp 安全风险与防护课堂开课了!

    本文由葡萄城技术团队于原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 2018 网络安全事故频发,从数据泄露.信息窃取,到 DDOS 攻击.勒索 ...

  10. 【IntelliJ IDEA】代码中出现Usage of API documented as @since 1.8+ more..

    在idea中写代码过程中.有这种报错出现: Usage of API documented as @since 1.8+ more.. 修改JDK版本的几个地方 最后,在pom.xml文件中添加: & ...