User login (struts2) processing for app server-side development

The app basically has operations related to user registration and login, so what does the server need to do after login? When the user initiates other requests, how to determine the uniqueness of the user and associate the app user with the server based on what?

I have asked some novices before, and found that many novices use the following method: when the user logs in, verify the account password, and if it is correct, return a unique UserId corresponding to the user in the user table to the app, and then the app's Requests carry this UserId, so as to associate the app with the server, and use the UserId to perform query and other related interface operations. When performing an operation, query User every time according to UserId, and then perform various operations. But is this right? Just imagine, if this is the case, the communication relationship depends on a UserId, then it doesn't matter whether you are logged in or not, as long as you know the id, any interface operation, such as getting all orders, withdrawing cash, etc., is maintained by this id . This is definitely a problem. Many interface operations cannot initiate requests without logging in, such as some critical order information, account balance information, payment requests, etc., but some interfaces can be accessed without logging in. , such as the banner of advertisements, the display of products, etc. If you rely on UserId to associate, how do you know whether the user is logged in? Anyway, all operations can be performed through UserId. There are even some User table primary key generation strategies that use int-type increments, so this is simpler. Just guess an id, and you can perform all operations on the user. Isn't it very dangerous.

In fact, to the server, the login operation is a special operation that represents a session. Let's take a look back, several built-in objects in http requests, page, request, session, application. The request and session are used here. request represents the request object, and session represents the session object. Request acts within the scope of a request, for example, what are you going to do this time, to achieve a purpose. If you want to pass something, use request, only once. The session is a reply, its destruction is the session expiration, the default is 30 minutes, it can be modified, and the session will also be destroyed when the browser is closed. Session can be understood as a conversation, such as you and a person talking, the information exchanged between the two of you can interact multiple times. It can be seen from this that each request initiated by the app is a request. You request the server, and the server returns a value to you. Then the session is used to save the session after login. Once the app is logged in, the user has a unique session_id in this session. This is the only sign of the interaction between the app user and the server. When the user logs out or the session expires, the association between the user and the server is stopped. The next time you log in, there will be a new session_id.

The unique identifier UserId of the User table should not be exposed to the app client, and the association should be based on the session session. The correct operation should be that after logging in, the server saves the session state, stores the user's unique identifier in the session, and then returns the session_id to the client. The next time the app makes a request with the session_id. The server verifies the session. If the session is still there, it means that the user has logged in. If not, it means that the login has been logged out, or the session has expired, so that the user's primary key UserId will not be exposed and the interface will be avoided.

Let's talk about how to use struts to do this. Struts has its own interceptor interceptor, which can intercept some requests and some not. Very convenient.

I will not post the complete code for some codes, and I will not write those configurations, so I will talk about the general process.

我们先来写一个拦截器,SessionInterceptor.java

package mobile.util.interceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts2.StrutsStatics;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

/**
 * 手机端校验是否登录的拦截器
 * 
 * @author wolf
 *
 */
public class SessionInterceptor implements Interceptor {

	private static final long serialVersionUID = -520686124206452492L;

	public void destroy() {

	}

	public void init() {

	}

	public String intercept(ActionInvocation invocation) throws Exception {
		ActionContext actionContext = invocation.getInvocationContext();
		HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST);
		HttpServletResponse response = (HttpServletResponse) actionContext.get(StrutsStatics.HTTP_RESPONSE);
		
        HttpSession session = request.getSession();
		
		// 获取sessionid
		String sessionId = session.getId();
		response.addHeader("sessionId", sessionId);

		String actionName = invocation.getAction().toString();
		// 不拦截以下action
		if (actionName.contains("LoginAction") || actionName.contains("registRequestCode") || actionName.contains("verifyCode")) {
			return invocation.invoke();
		}
		
		// 没保存过用户session,说明没登录,或者session过期
		if (session.getAttribute(sessionId) == null) {
			// 用户未登录,跳到没登录处理的action
			session.invalidate();
			response.sendRedirect(request.getContextPath() + "/mobile/NoLoginAction.action");
			return null;
		}

		return invocation.invoke();
	}

}

 在这个拦截器里,intetcept方法,能够获取到所有通过这个拦截器拦截的请求,并且做相应的处理,先获取session对象,把sessionId放到response的header里,将来返回给app用。然后有一些请求是在不登录的情况下也能访问的,不拦截的,这里我通过判断请求名字来确定哪些不需要拦截,譬如登录、注册、发验证码之类的,就不需要做拦截。其他的需要拦截的,就在session里获取attribute,来看这个sessionId里存的对象是否为空,如果空了,说明没登录或已超时,就跳转到没登录的处理去。不为空的话就invoke放行。那些session里存什么东西就由大家自行决定。在什么时候在session里存信息呢,当然是在登录成功后了。

 

下面是LoginAction的一段代码,里面有一些是自己的逻辑,不适用于别的项目,所以就看看思想就好了

public String logout() {
		HttpServletRequest request = ServletActionContext.getRequest();
		request.getSession().invalidate();
		
		BaseData basedata = new BaseData();
		basedata.setCode(1);
		PrintUtil.print(JsonUtil.toJsonString(basedata));
		
		return null;
	}
	
	/**
	 * 登录
	 * @return
	 */
	public String login() {
		OlderManReturnBean returnBean = new OlderManReturnBean();
		List<TbOlderMan> olderMans = olderManService.queryByName(userName);
		if(olderMans.size() == 0) {
			//用户不存在
			returnBean.setCode(-1);
		} else if(!olderMans.get(0).getLoginPwd().equals(MD5.toMD5(password))) {
			//密码错误
			returnBean.setCode(-2);
		} else {
			//登录成功
			returnBean.setCode(0);
			returnBean.setOlderMan(olderMans.get(0));
			HttpServletRequest request = ServletActionContext.getRequest();
			request.getSession().setAttribute(request.getSession().getId(), olderMans.get(0).getOlderManId());
			request.getSession().setMaxInactiveInterval(20);
		}
		PrintUtil.print(JsonUtil.toJsonString(returnBean));
		
		return null;
	}

 登录成功后,在session里put进去值,key就是sessionId,value是用户的UserId。下次用户发请求时,带着sessionId来请求,我们就从session里getAttribute(sessionId),就能得到UserId了,如果得不到,说明已经不在登录状态了。通过拦截器来判断用户是否在登录状态,是否放行一些不需要登录就能访问的请求。

 

setMaxInactiveInterval方法是设置session超时时间,单位是秒,我这里设个20秒,方便测试session超时。可以通过浏览器来进行这个登录操作,登录成功后通过debug就能看到sessionId,然后随便输出个值。过20秒后,再试图访问一个其他的请求时,拦截器就会判断出该sessionId已经超时了,所以session去getAttribute时就会为空,然后就跳到没登录的action了。实际使用中请根据自己的需求来设置超时时间。

下面说一下struts.xml的配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
	<package name="mobile" namespace="/mobile" extends="json-default">

		<interceptors>
			<interceptor name="sessionInterceptor"
				class="mobile.util.interceptor.SessionInterceptor" />
			<interceptor-stack name="defaultStack">
				<interceptor-ref name="defaultStack" />
				<interceptor-ref name="sessionInterceptor" />
			</interceptor-stack>
		</interceptors>
		<default-interceptor-ref name="defaultStack" />

		<action name="NoLoginAction" class="mobile.action.base.NoLoginAction" />

		<!-- 登录、注册、修改密码 -->
		<action name="*LoginAction" class="mobile.action.LoginAction"
			method="{1}" />

		<action name="*SmsAction" class="mobile.action.SmsAction"
			method="{1}" />

		<action name="*OlderManAction" class="mobile.action.olderman.OlderManAction"
			method="{1}" />
		<action name="*UrgentPersonAction" class="mobile.action.olderman.UrgentPersonAction"
			method="{1}" />
	</package>
</struts>    

 在这个package里,写明用的interceptor,将来所有这个namespace下的请求都会先走一遍拦截器,你可以通过写多个struts-*.xml,来区分不同的package,使用不同的拦截器,或者有的action不使用拦截器,这个就看自己的业务了。注意,struts是靠package来区分的,一个package下都会走这个拦截器。所以就有两种方式来决定是否拦截某些请求,一种就是在上面的拦截器代码里通过action的name来设置,还有就是通过有的package写拦截器,有的不写,或者两种方法同时使用来进行复杂的逻辑判断,拦截特定的请求。

以上就是app登录后,服务器端应该做的处理,和拦截器相关的处理。

 

http://blog.csdn.net/tianyaleixiaowu/article/details/50616939

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326475554&siteId=291194637