关于Token在Android中实现用户登录的使用

原理

在安卓中实现用户登录一般都是用Token,而目前最流行的就是用jwt先讲一下实现的原理:第一步:用户第一次登录,客户端向服务端发送用户和密码,服务端验证用户密码是否正确,如果不正确返回客户端一个消息(用户名错误或者密码错误),如果正确,服务端生成一个Token,并且缓存起来(可以用Redis或者存放数据库)。第二步:客户端接收服务端发送的Token和登陆成功的标识,并且把Token也保存起来,并跳转到登录成功后的页面。第三步:登陆成功后有其他向服务端请求数据的请求,一律在请求头部携带客户端保存的Token,服务端验证这些请求携带的Token是否过期或者不对,正常就返回正常的数据,失败就返回验证Token失败的信息,客服端接收失败的信息提示用户重新登陆,并跳转到登录页。

流程图

Android token校验 安卓token登录器_Android token校验

前台

第一步:用户第一次登录,客户端向服务端发送用户和密码,

try{
            String loginurl = getString(R.string.url2) + "login";

                //自己写的工具类
            YyHttpRequestOrGetDataFromNet yyHttpRequestOrGetDataFromNet = new YyHttpRequestOrGetDataFromNet();
//以下采用的是将accountid和credential放到JsonObject对象中,
// 因为后台/login设置的参数是一个user对象
                JSONObject jsonParam = new JSONObject();
                jsonParam.put("credential", password);
                jsonParam.put("accountid", accountid);
//                System.out.println("token:"+yyHttpRequestOrGetDataFromNet.doPost(loginurl,jsonParam));
//把第一次登录服务器生成的Token存在本地

// json格式化
                jsonLoginningInfo = yyHttpRequestOrGetDataFromNet.doPost(loginurl,jsonParam);
                Gson gson = new Gson();
                jsonRootBean = gson.fromJson(jsonLoginningInfo,new TypeToken<JsonRootBean>(){}.getType());
//token 存储

                YySharedPrefUtility.setParam(LoginActivity.this,YySharedPrefUtility.Token,
                        jsonRootBean.getContent().getToken());
                System.out.println("tokrn:"+jsonRootBean.getContent().getToken());
                System.out.println("tokrn:"+jsonRootBean.getMsg());


            }
            catch (Exception e){ e.printStackTrace();}

            //密码正确:服务端返回1
            if (jsonRootBean.getStatus()==0&&jsonRootBean.getMsg().equals("loginSuccess")) {
                Toast.makeText(this, "登陆成功", Toast.LENGTH_SHORT).show();
                YySharedPrefUtility.setParam(LoginActivity.this,
                        YySharedPrefUtility.ACCOUNTID, accountid);//用户名存起来
                startActivity(new Intent(getApplicationContext(), MainActivity.class));//登录成功跳转首页

            }
            //用户名不存在或密码错误:服务端返回-1
            else {
                Toast.makeText(this, "用户名不存在或密码不正确", Toast.LENGTH_SHORT).show();
            }

这是我改动的工具类

post请求:

public String doPost(String url, JSONObject jsonParam) throws Exception {

        /* Translate parameter map to parameter date string */

        System.out.println("POST parameter : " + jsonParam.toString());
//以下两行代码非常有用,是网络连接一个严格的格式
        //原文博客见
        StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);
    //创建URL连接
        URL localURL = new URL(url);

        URLConnection connection = this.openConnection(localURL);
        HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
        httpURLConnection.setDoOutput(true);
        httpURLConnection.setRequestMethod("POST");//请求方法为Post
        httpURLConnection.setRequestProperty("Accept-Charset", charset);
        httpURLConnection.setRequestProperty("Content-Type", "application/json");
        httpURLConnection.setUseCaches(false);//post不能设置缓存


        OutputStream outputStream = null;
        OutputStreamWriter outputStreamWriter = null;
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader reader = null;
        StringBuffer resultBuffer = new StringBuffer();
        String tempLine = null;

        try {
            outputStream = httpURLConnection.getOutputStream();
            outputStreamWriter = new OutputStreamWriter(outputStream);
            //这个地方最关键,将登录传过来的账户和密码
            outputStreamWriter.write(jsonParam.toString());
            outputStreamWriter.flush();
           //判断请求是否成功
            if (httpURLConnection.getResponseCode() >= 300) {
                throw new Exception("HTTP Request is not success, Response code is " + httpURLConnection.getResponseCode());
            }
            //接收响应流
            inputStream = httpURLConnection.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream);
            reader = new BufferedReader(inputStreamReader);

            while ((tempLine = reader.readLine()) != null) {
                resultBuffer.append(tempLine);
            }

        } finally {

            if (outputStreamWriter != null) {
                outputStreamWriter.close();
            }

            if (outputStream != null) {
                outputStream.close();
            }

            if (reader != null) {
                reader.close();
            }

            if (inputStreamReader != null) {
                inputStreamReader.close();
            }

            if (inputStream != null) {
                inputStream.close();
            }

        }

        return resultBuffer.toString();//返回数据
    }

get请求:

//获取JSON数据流数据
    public static String doGetJsonStringFromThread(final String u,final String token) {
        Thread newThread;
        newThread = new Thread(new Runnable() {

            @Override
            public void run() {

                //创建url对象
                URL url = null;
                try {
                    //实例化url
                    url = new URL(u);
                    //获取HttpURLConnection
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    //设置get请求
                    connection.setRequestMethod("GET");
                    //设置超时时间
                    connection.setConnectTimeout(5 * 1000);
                    //设置编码
                    connection.setRequestProperty("contentType", "utf-8");
                    //注意,最重要的地方,通过setRequestProperty把Token放到请求头
                    connection.setRequestProperty("token",token);
                    //连接
                    connection.connect();
                    //获取连接响应码
                    int code = connection.getResponseCode();

                    //响应失败
                    if (code >= 300) {
                        throw new Exception("HTTP Request is not success, Response code is " + code);
                    }
                    //如果连接上
                    if (code == 200) {

//                        h.sendEmptyMessage(2);
                        //获取数据
                        InputStream inputStream = connection.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        String line;

                        StringBuffer buffer = new StringBuffer();
                        while ((line = bufferedReader.readLine()) != null) {
                            buffer.append(line);

                        }
                        //获取json
                        jsonBuffer = buffer.toString();
                        //关闭is
                        inputStream.close();
                    }
                    //关闭连接
                    connection.disconnect();

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        newThread.start(); //启动线程
        try {
            //join方法:让主线程等待子线程运行结束后再继续运行
            newThread.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return jsonBuffer;
    }

后台

1.拦截器:客户端每像服务端发送请求都要在这里接受一下验证,如果Token失效或者是伪造的Token都会验证出来返回客户端错误的信息

public class JWTInterceptor implements HandlerInterceptor{
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException{
		// TODO Auto-generated method stub
	
   	 String token = request.getHeader("token");

    	try{
        	JWTUtils.verify(token);
       	 return true;
   	 }catch (Exception e){
    		JsonRootBean sJsonBaseObject=new JsonRootBean(); 
    		sJsonBaseObject.setMsg("令牌验证失败");
    		sJsonBaseObject.setStatus(-1);
        	ObjectMapper objectMapper = new ObjectMapper();
       	    String result = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(sJsonBaseObject);
        	response.setContentType("application/json;charset=UTF-8");
        	response.getWriter().println(result);

        	return false;
    	}
	}
}

2.jwt工具类

public class JWTUtils {
     token密钥(自定义),最好在网上在线生成一个随机字符串,我这里是瞎打的
    //这个密钥一定不能泄露
	private static final String SING = "!@#$%%^&&*####%%%$%";
    //生成Token
	public static String getToken(Map<String,String> map){
    	Calendar instance = Calendar.getInstance();
    	instance.add(Calendar.HOUR,5);
    	JWTCreator.Builder builder = JWT.create();
    	map.forEach((k,v)->{
        	builder.withClaim(k,v);
    	});
    	String token = builder.withExpiresAt(instance.getTime())
            	.sign(Algorithm.HMAC256(SING));

    	return token;
	}
//根据密钥生成JWT效验器
	public static void verify(String token){//解析Token
    	JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
	}
//效验TOKEN
	public static DecodedJWT getTokenInfo(String token){
    	return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
	}
	}

3.spring.mvc 写在标签的最外面,因为客户端要通过/login来获取Token,所以不能被拦截

<!-- 配置拦截器,验证Token -->
  <mvc:interceptors>
		<mvc:interceptor>
			<!-- 拦截所有/目录下面的页面 -->
			<mvc:mapping path="/**"/>
			<!-- mvc:exclude-mapping是另外一种拦截,它可以在你后来的测试中对某个页面进行不拦截 -->
			<mvc:exclude-mapping path="/login" />
			<bean class="com.yunyou.DBI.interceptor.JWTInterceptor"></bean>			
		</mvc:interceptor>
	</mvc:interceptors>

4.controller层

其他等等服务层,实体类就没必要给出来了,这里给了一个控制层

@Controller
public class UserLoginningInfoController {
	@Autowired
	private UserLoginningInfoService uService;
@RequestMapping(value="login",method=RequestMethod.POST)
	@ResponseBody
	public JsonRootBean login(@RequestBody v_U_userLoginning_info user) {
		System.out.println("user"+user.getAccountid()+" "+user.getCredential());
		JsonRootBean uJsonBaseObject = new JsonRootBean();
		v_U_userLoginning_info us = uService.findUserByPassword(
				user.getAccountid(), user.getCredential());
		if(us==null) {
			uJsonBaseObject.setMsg("loginError");
			uJsonBaseObject.setStatus(-1);
			return uJsonBaseObject;
		}
		HashMap<String,String> payload = new HashMap<String,String>();
		payload.put("accountid", us.getAccountid());
		String token = JWTUtils.getToken(payload);
		LoginToken loginToken = new LoginToken();
		loginToken.setToken(token);
		uJsonBaseObject.setContent(loginToken);
		uJsonBaseObject.setMsg("loginSuccess");
		return uJsonBaseObject;
	}

最后就可以啦