您的位置:首页 > 其它

对天乙社区bbscs8实现的详细分析十三

2008-07-14 11:19 363 查看
此文为转载:http://www.diybl.com/course/1_web/webjs/2007113/82989.html

OK!我们回到login.bbscs?action=check,这将getAction()-->check!首先它将执行execute方法:
public String execute() {
this.setUrlRewrite(Constant.USE_URL_REWRITE); //public static boolean

USE_URL_REWRITE = false;
this.setUserAuthCodeValue();
....
接下来,根据if (this.getAction().equalsIgnoreCase("index")) {...
}if (this.getAction().equalsIgnoreCase("admin")) {..
}if (this.getAction().equalsIgnoreCase("login")) {
return this.login();
}

if (this.getAction().equalsIgnoreCase("check")) {
return this.check();
}
来进行流程的选择(这就是所为的逻辑吧)!
public String check() { //对cookie的检测!
if (StringUtils.isNotBlank(this.getUserCookie().getUserName())
&& StringUtils.isNotBlank(this.getUserCookie().getPasswd()))

{
return this.cookieLogin();//有cookie
} else {
return this.index();
}
}
--->
public String index() {
this.setAction("login");
this.setHiddenLogin(0);
if (Constant.USE_URL_REWRITE) {
tourl = this.getBasePath() + "main.html"; //注意,曾经有sb.append

("/");
} else {
tourl = this.getBasePath() +

BBSCSUtil.getActionMappingURLWithoutPrefix("main");//此工具方法加后缀main.bbscs
}

return this.input();
}
-->
public String input() {//是否要登录
if (this.getSysConfig().getUsePass() == 0) {//usePass=1表示使用通行证登录
return

INPUT;//action=login,hiddenLogin=0,tourl=XXXX:80/main.bbscs,urlRewrite=false,userAuthCodeVal

ue,注意到:
private boolean urlRewrite = false;
private boolean useAuthCode = true;
private int cookieTime = -1;
还有basePath,remoteAddress,UserCookie,以及两组List等等} else {
this.setActionUrl(this.getSysConfig().getPassUrl

());//PassUrl=http://www.laoer.com/login.do
return "loginPass";
}
}
我们返回struts.xml中可以找到它将result到哪里:
<result name="success" type="redirect">${tourl}</result>
<result name="input">/WEB-INF/jsp/login.jsp</result>
<result name="loginPass">/WEB-INF/jsp/passLogin.jsp</result>
好,我们已经INPUT到/WEB-INF/jsp/login.jsp界面中了:
<%@page contentType="text/html; charset=UTF-8"%>
<%@taglib uri="/WEB-INF/struts-tags.tld" prefix="s"%>
<%@taglib uri="/WEB-INF/bbscs.tld" prefix="bbscs"%>
另外还有<%@ taglib uri="/WEB-INF/FCKeditor.tld" prefix="FCK" %>
其中的,s是struts2的,而bbscs是本系统的...
<%@page contentType="text/html; charset=UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" +

request.getServerPort() + path + "/"; //basePath!
%>

其中,bbscs:webinfo是网站信息用的标签!<title><bbscs:webinfo type="forumname"/> - <s:text

name="login.title"/><bbscs:webinfo type="poweredby"/></title>
<tag>
<name>webinfo</name>
<tag-class>com.laoer.bbscs.web.taglib.WebInfoTag</tag-class>//WebInfoTag
<body-content>empty</body-content> //无内容的!
<attribute>
<name>type</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue> //run time expression value运行时表

达式
</attribute>
</tag>
我们进入WebInfoTag一看:它有一个属性type及其get/set方法
public Component getBean(ValueStack arg0, HttpServletRequest arg1,

HttpServletResponse arg2) {
return new WebInfo(arg0, pageContext); //构造一个Component
}

protected void populateParams() {
super.populateParams();
WebInfo tag = (WebInfo) component;
tag.setType(type);
}
而WebInfo实现了Component接口,它的构造方法:
public WebInfo(ValueStack stack, PageContext pageContext) {
super(stack);
this.pageContext = pageContext;
}
这里关键的地方是:
public boolean start(Writer writer) {
boolean result = super.start(writer);
WebApplicationContext wc =

WebApplicationContextUtils.getWebApplicationContext(this.pageContext
.getServletContext()); //调用服务层
SysConfig sysConfig = (SysConfig) wc.getBean("sysConfig");//这里主要用了

sysConfg
StringBuffer sb = new StringBuffer();
if (this.getType().equalsIgnoreCase("forumname")) { //type="forunname"
sb.append(sysConfig.getForumName());
}

if (this.getType().equalsIgnoreCase("poweredby")) {//type="poweredby"
sb.append(" - ");
sb.append("Powered By BBS-CS[天乙社区]");
}

if (this.getType().equalsIgnoreCase("meta")) {//type="meta"
sb.append("<meta name="keywords" content="");
sb.append(sysConfig.getMetaKeywords());
sb.append(""/> ");
sb.append("<meta name="description" content="");
sb.append(sysConfig.getMetaDescription());
sb.append(""/>");
}
if (this.getType().equalsIgnoreCase("pagefoot")) {//type="pagefoot"
Locale locale = this.pageContext.getRequest().getLocale();
ResourceBundleMessageSource messageSource =

(ResourceBundleMessageSource) wc.getBean("messageSource");//从消息资源文件获得
if (StringUtils.isNotBlank(sysConfig.getWebName())) {
if (StringUtils.isNotBlank(sysConfig.getWebUrl())) {
sb.append("<a href="");
sb.append(sysConfig.getWebUrl());
sb.append("" target="_blank">");
sb.append(sysConfig.getWebName());
sb.append("</a>");
} else {
sb.append(sysConfig.getWebName());
}
}
if (StringUtils.isNotBlank(sysConfig.getForumName())) {
sb.append(" | ");
if (StringUtils.isNotBlank(sysConfig.getForumUrl())) {
sb.append("<a href="");
sb.append(sysConfig.getForumUrl());
sb.append("" target="_blank">");
sb.append(sysConfig.getForumName());
sb.append("</a>");
} else {
sb.append(sysConfig.getForumName());
}
}
if (StringUtils.isNotBlank(sysConfig.getWebmasterEmail())) {
sb.append(" | ");
sb.append("<a href="mailto:");
sb.append(sysConfig.getWebmasterEmail());
sb.append("">");
sb.append(messageSource.getMessage("bbscs.contactus", null,

locale));
sb.append("</a>");
}
if (StringUtils.isNotBlank(sysConfig.getPrivacyUrl())) {
sb.append(" | ");
sb.append("<a href="");
sb.append(sysConfig.getPrivacyUrl());
sb.append("" target="_blank">");
sb.append(messageSource.getMessage("bbscs.privacy", null,

locale));
sb.append("</a>");
}
if (StringUtils.isNotBlank(sysConfig.getCopyRightMsg())) {
sb.append("<BR/>");
sb.append(sysConfig.getCopyRightMsg()); //加入版权信息
}
sb.append("<BR/>");
sb.append("<strong><font face="Tahoma" size="1" color="#A0A0A4

">");
sb.append("Powered By ");
sb.append("<a href="http://www.laoer.com" target='_blank'>BBS-

CS</a>");
sb.append(" V");
sb.append(Constant.VSERION);
sb.append(" © 2007</font></strong>");
}

try {
writer.write(sb.toString()); //输入
} catch (IOException e) {
e.printStackTrace();
}

return result;
}
我们看login.jsp中,有许多struts2的标签,如s:form s:hidden s:text s:actionerror s:textfield

s:if s:else s:radio s:submit s:submit s:url (样式用cssClass)对于具体的使用请

看:http://www.blogjava.net/max/archive/2006/10/18/75857.html
注意<img alt="<s:text name="login.authcode"/>" src="authimg" align="absmiddle" />是从authimg

得到图片的(注意这里是相对URL)
也注意到:s:actionerror也用到了template.bbscs0 <s:actionerror theme="bbscs0"/>
<#if (actionErrors?exists && actionErrors?size > 0)>
<div class="errormsg">
<#list actionErrors as error>
<span class="errorMessage">${error}</span><br/>
</#list>
</div>
</#if>
注意到struts.properties文件中:
struts.ui.theme=simple
//struts.ui.templateDir=template 默认
//struts.ui.templateSuffix=ftl 默认
好的,我们提交表单,进入login.bbscs,还是最终达到Login.java
public String execute() {
this.setUrlRewrite(Constant.USE_URL_REWRITE);
this.setUserAuthCodeValue();
-->
private void setUserAuthCodeValue() {
this.setUseAuthCode(this.getSysConfig().isUseAuthCode()); //=true
}
if (this.getAction().equalsIgnoreCase("login")) {
return this.login();
}
--->
public String login() {
if (StringUtils.isBlank(this.username) || StringUtils.isBlank(this.passwd))

{ //输入的帐号和密码是否为否
this.addActionError(this.getText("error.nullerror"));
return INPUT;
}

UserInfo ui = this.getUserService().findUserInfoByUserName(this.getUsername

());//查找有没有这个用户
if (ui == null) {
this.addActionError(this.getText("error.user.notexist"));
return INPUT;
}
if (this.getSysConfig().isUseSafeLogin()) { //是否安全登录模式(例如3次登录机

会)
if (this.getLoginErrorService().isCanNotLogin(ui.getId())) {
this.addActionError(this.getText("error.login.times"));
return INPUT;
}
}

if (!Util.hash(this.getPasswd()).equals(ui.getRePasswd())) { // 密码错误
/**
public synchronized static final String hash(String data) {
if (digest == null) {
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException nsae) {
System.err
.println("Failed to load the MD5

MessageDigest. " + "We will be unable to function normally.");
nsae.printStackTrace();
}
}
// Now, compute hash.
digest.update(data.getBytes());
return encodeHex(digest.digest());
}

*/
if (this.getSysConfig().isUseSafeLogin()) {
try {
this.getLoginErrorService

().createLoginErrorui.getId());//加入错误服务中!
} catch (BbscsException ex1) {
logger.error(ex1);
}
}
this.addActionError(this.getText("error.login.passwd"));
return INPUT;
}

if (this.getSysConfig().isUseAuthCode()) { //使用验证码
String cauthCode = this.getUserCookie().getAuthCode();//Cookie中得到

AuthCode!

if (StringUtils.isBlank(cauthCode) || !cauthCode.equals

(this.getAuthCode())) {
this.addActionError(this.getText("error.login.authcode"));
return INPUT;
}
}

ui.setLastLoginIP(ui.getLoginIP());//上一次的
ui.setLastLoginTime(ui.getLoginTime());//上一次

ui.setLoginIP(this.getRemoteAddr());
ui.setLoginTime(new Date()); //时间类型哦
ui.setUserLocale(this.getLocale().toString());

long nowTime = System.currentTimeMillis();
UserOnline uo = new UserOnline();
uo.setAtPlace("");
uo.setBoardID(0);
uo.setNickName(ui.getNickName());
uo.setOnlineTime(nowTime);//long类型的时间
uo.setUserGroupID(ui.getGroupID());
uo.setUserID(ui.getId());
uo.setUserName(ui.getUserName());
uo.setValidateCode(ui.getId() + "_" + nowTime);//构造出来的,用于避免重复登录

吧!
if (this.getHiddenLogin() == 1 || ui.getHiddenLogin() == 1) { // 用户隐身登


uo.setHiddenUser(1);
}

try {
ui = this.getUserService().saveAtLogin(ui); // 用户登录处理
/**
public UserInfo saveAtLogin(UserInfo userInfo) throws BbscsException {
try {
if ((System.currentTimeMillis() - userInfo.getLastLoginTime

().getTime()) > 30 * 60000) {
userInfo.setLoginTimes(userInfo.getLoginTimes() + 1);//不一

样吧!
userInfo.setExperience(userInfo.getExperience() + 1);
}
userInfo = this.getUserInfoDAO().saveUserInfo(userInfo);
this.getUserInfoFileIO().writeUserFile(userInfo);
return userInfo;
} catch (Exception ex) {
logger.error(ex);
throw new BbscsException(ex);
}
}
*/
uo = this.getUserOnlineService().createUserOnline(uo); // 加入在线用

户表
} catch (BbscsException ex) {
logger.error(ex);
return INPUT;
}

UserSession us = userService.getUserSession(ui);
/**
public UserSession getUserSession(UserInfo ui) {
UserSession us = new UserSession();
us.setEmail(ui.getEmail());
us.setGroupID(ui.getGroupID());
us.setId(ui.getId());
us.setNickName(ui.getNickName());
String[] signDetail = new String[3];
signDetail[0] = ui.getSignDetail0() == null ? "" : ui.getSignDetail0();
signDetail[1] = ui.getSignDetail1() == null ? "" : ui.getSignDetail1();
signDetail[2] = ui.getSignDetail2() == null ? "" : ui.getSignDetail2();
us.setSignDetail(signDetail);
us.setUserName(ui.getUserName());
us.setLastActiveTime(System.currentTimeMillis());

Map[] permissionMap = this.getUserPermission(ui);

us.setUserPermissionArray(permissionMap);
-->
/**
public Map[] getUserPermission(UserInfo userInfo) {
return this.getUserPermission(userInfo.getGroupID());
}
*/
return us;
}
*/

us.setValidateCode(uo.getValidateCode());//Session的validateCode改变之

this.getSession().put(Constant.USER_SESSION_KEY, us);
放入本Login本关的Session中!public static final String USER_SESSION_KEY = "user_session";这里

我们可以简单的看一下UserSession的处理,好象我们以前讲过吧,这里重新讲一次:
private String userName = "";
private String id = "";
private String nickName = "";
private String email = "";
private long lastActiveTime = 0;
private Map userPermission = new HashMap();
private Map boardPermission = new HashMap();
private Map specialPermission = new HashMap();
private Map boardSpecialPermission = new HashMap();
private long bid = 0;
private int groupID = 0;
private long addedOnlineTime = 0;
private long addedOnlineHour = 0;
private String validateCode = "";
private String[] signDetail = { "", "", "" };
private String boardPass = "";
private int initStatus = 0;
这些是它的属性,当然也有get/set;上面的us.setValidateCode就是这样工作的..我们这里重点看下:
us.setUserPermissionArray(permissionMap);
public void setUserPermissionArray(Map[] permissionMap) {
setSpecialPermission(permissionMap[1]); //特别的权力!
/**
public void setSpecialPermission(Map specialPermission) {
this.specialPermission = specialPermission;
}
而它是通过根据Permission的TypeID确定的:
Permission permission = (Permission) permissionList.get(i);
if (permission.getTypeID() == 0) {
userPermission[0].put

(permission.getResource() + "," + permission.getAction(), permission);
} else {
userPermission[1].put

(permission.getId(), permission);
}
*/
Set pset = permissionMap[0].entrySet();//Map的遍历哦!
Iterator it = pset.iterator();
while (it.hasNext()) {
Map.Entry p = (Map.Entry) it.next();
Permission permission = (Permission) p.getValue();//getValue
String[] actions = permission.getAction().split(",");
for (int i = 0; i < actions.length; i++) {
String[] resources = ((String) p.getKey()).split

(",");//getKey
this.getUserPermission().put(resources[0] + "?action=" +

actions[i], p.getValue());
}
}

}
this.getUserCookie().removeAuthCode(); //Cookie的authCode改变
this.getUserCookie().addCookies(ui);
// this.getUserCookie().addValidateCode(uo.getValidateCode());
if (this.getCookieTime() != -1) {
this.getUserCookie().addC("U", this.getUsername(),

this.getCookieTime());
this.getUserCookie().addDES("P", Util.hash(this.getPasswd()),

this.getCookieTime());//这里对UserSession和UserCookie都进行了改变...
}

return SUCCESS;
}
我们知道在进入Login之前,已经对UserCookie进行了操作:
UserCookie userCookie = new UserCookie(request, response, sysConfig);
((UserCookieAware) action).setUserCookie(userCookie);
看下面授代码:
public UserCookie(HttpServletRequest request, HttpServletResponse response, SysConfig

sysConfig) {
this.request = request;
this.response = response;
this.sysConfig = sysConfig;
try {
des = new DES(DES._DESede);//DES算法
/**
DES 64位密钥, 有效密钥56位, 8位用来校验.
DES ede, 密钥应该是64*2=128位, 有效密钥56*2=112位 -->16字节
Blowfish 密钥40--448位.
*/
} catch (Exception ex) {
logger.error(ex);
}
getCookies();
}
从request,response原处引入这样参数到UserCookie中!
private HttpServletRequest request;
private HttpServletResponse response;
private SysConfig sysConfig;
private DES des;
getCookies...将查找如下key相关的Cookie信息:
private static final String PASS_USERNAME_KEY = "PASS_USERNAME";//用于单点登录
private static final String PASS_USERNAME_DES_KEY = "PASS_USERNAME_DES";//用于单点登


private static final String BBSCS_FORUMPERNUM_KEY = "FN";
private static final String BBSCS_POSTPERNUM_KEY = "PN";
private static final String BBSCS_TIMEZONE_KEY = "TZ";
private static final String BBSCS_FORUMVIEWMODE_KEY = "VM";
private static final String BBSCS_LASTSENDNOTETIME_KEY = "LN";
private static final String BBSCS_LASTPOSTTIME_KEY = "LP";
private static final String BBSCS_EDITTYPE = "ET";
private static final String BBSCS_AUTHCODE = "AC";
private static final String BBSCS_USERNAME = "U";//用于BBSCS
private static final String BBSCS_PASSWD = "P";//用于BBSCS
当然,它们也有初始值:
private int postPerNum = 10;
private int forumPerNum = 20;
private int forumViewMode = 0;
private String timeZone = "GMT+08:00";
private String pusername = "";
private String pusernamedes = "";
private long lastSendNoteTime = 0;
private long lastPostTime = 0;
private int editType = 0;
private String authCode = "";
private String userName = "";
private String passwd = "";
这里有request的使用Cookie cookies[] = request.getCookies();
if (this.sysConfig.isUsePass()) { /**数据库UsePass=0,usePass=1可能指的是用于多个系

统之间的登录问题(使用通行证)*/
if (sCookie.getName().equals

(PASS_USERNAME_KEY)) {
this.pusername = sCookie.getValue();
// System.out.println("pass

username:" + username);
}
if (sCookie.getName().equals

(PASS_USERNAME_DES_KEY)) {
if (StringUtils.isNotBlank

(sCookie.getValue())) {
buf = Util.base64decodebyte

(sCookie.getValue());
byte[] dec = des.decode(buf,

Util.base64decodebyte(this.sysConfig.getCookieKey()));//Enc-Base64位加密
this.pusernamedes = new

String(dec);
// System.out.println("pass

usernamedes:" +
// usernamedes);
}
}
}
我们看验证码的一段:
if (sCookie.getName().equals(BBSCS_AUTHCODE)) {
if (StringUtils.isNotBlank(sCookie.getValue

())) {
buf = Util.base64decodebyte

(sCookie.getValue());
byte[] dec = des.decode(buf,

Util.base64decodebyte(this.sysConfig.getCookieKey()));
this.authCode = new String(dec);
}
}
而我们回到AuthImg:
UserCookie uc = new UserCookie(request, response, sysConfig);
uc.addAuthCode(rand);//这里用了UserCookie中的addAuthCode方法:
public void addAuthCode(String authCode) {
this.addDES(BBSCS_AUTHCODE, authCode, -1);
}
//而对于authCode其实它用了DES算法:
public void addC(String name, String value, int maxage) { //普通加Cookie的方法
Cookie cookies = new Cookie(name, value);
cookies.setPath(this.sysConfig.getCookiePath());
cookies.setMaxAge(maxage);
// cookies.setMaxAge(30 * 60);
if (StringUtils.isNotBlank(this.sysConfig.getCookieDomain())) {//域名,用于

单点登录
cookies.setDomain(this.sysConfig.getCookieDomain());
}
this.response.addCookie(cookies);//这里用到了response!
}

public void addDES(String name, String value, int maxage) {
try {
// DES des = new DES(DES._DESede);
des.setKey(Util.base64decodebyte(this.sysConfig.getCookieKey()));//

加入密钥!
/**数据库中CookieKey=nhNhwZ6X7xzgXnnZBxWFQLwCGQtJojL3*/
byte[] enc = des.encode(value.getBytes());
value = Util.base64Encode(enc);
/**
public static String base64Encode(byte[] txt) {
String encodeTxt = "";
if (txt != null && txt.length > 0) {
encodeTxt = new sun.misc.BASE64Encoder().encode(txt);
}
return encodeTxt;
}
*/
Cookie cookies = new Cookie(name, value);
cookies.setPath(this.sysConfig.getCookiePath());
// cookies.setMaxAge(30 * 60);
cookies.setMaxAge(maxage);
if (StringUtils.isNotBlank(this.sysConfig.getCookieDomain())) {
cookies.setDomain(this.sysConfig.getCookieDomain());
}
this.response.addCookie(cookies);
} catch (Exception ex) {
// ex.printStackTrace();
logger.error("addDES(String name, String value)" + ex);
}
}
好,我们暂时回到Login.java:
this.getUserCookie().removeAuthCode();
/**
public void removeAuthCode() {
this.addC(BBSCS_AUTHCODE, "", 0);
}
*/
this.getUserCookie().addCookies(ui);
// this.getUserCookie().addValidateCode(uo.getValidateCode());
if (this.getCookieTime() != -1) {
this.getUserCookie().addC("U", this.getUsername(),

this.getCookieTime());
this.getUserCookie().addDES("P", Util.hash(this.getPasswd()),

this.getCookieTime());
}
这里将一些登录特性ui用addCookies加入了其UserCookie中!
public void addCookies(UserInfo ui) {
this.forumPerNum = ui.getForumPerNum();
addC(BBSCS_FORUMPERNUM_KEY, String.valueOf(ui.getForumPerNum()), -1);
this.postPerNum = ui.getPostPerNum();
addC(BBSCS_POSTPERNUM_KEY, String.valueOf(ui.getPostPerNum()), -1);
this.timeZone = ui.getTimeZone();
addC(BBSCS_TIMEZONE_KEY, Util.base64Encode(ui.getTimeZone()), -1);
this.forumViewMode = ui.getForumViewMode();
addC(BBSCS_FORUMVIEWMODE_KEY, String.valueOf(ui.getForumViewMode()), -1);
this.editType = ui.getEditType();
addC(BBSCS_EDITTYPE, String.valueOf(ui.getEditType()), -1);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: