Android结合Retrofit实现统一加解密处理(Get、Post、Delete、Put)

Android中对接口进行统一加密

在之前的博客中我们介绍了 加密方案的选择Android中加解密需要注意的地方

本篇博客我们主要来看一下Android结合Retrofit进行加解密时的注意事项。

在开发过程中,接口是很多的,我们不可能分别对每个接口的请求数据都进行加密,这样写起来以及后期维护是非常麻烦的,所以,肯定要是统一处理的
还有我们常用的GetPostDeletePut请求他们的请求数据存放位置是不一样的,所以,我们需要对不同的请求方式做处理。
上传文件时,一般是不需要加密的,还有通过Retrofit请求第三方接口时也是不需要加密的,这些我们都需要考虑到。

目前来讲,我们最常使用的网络请求框架就是Retrofit了,Retrofit实际上就是对OkHttp的封装,网上的一些博客对加解密的处理是在转换器中处理的,实际上我认为这种方式并不好,首先我们来看一下GsonConverterFactory的源码.
在这里插入图片描述
看过源码你会发现,转换器只能对响应体和请求体进行处理,解密的时候还好说,加密的时候如果你使用的是Get或者Delete这中请求方式时,转换器是不好进行处理的。所以,关于Retrofit的统一加解密还是建议在拦截器中进行处理。

下面我们来总结一下注意事项:

  • 加解密要统一进行处理,方便维护
  • 加密时要对不同的加密方式进行不同的加密处理
  • 第三方接口,不加密
  • 上传时不加密

Retrofit 统一加密拦截器

拦截器对请求数据加密流程

  1. 获取请求的数据
  2. 对请求数据进行加密
  3. 根据不同的请求方式构造新的request

由于加密的相关逻辑需要跟后台商量,下面代码主要是看实现逻辑和注意事项,具体加密方法根据自身情况进行修改。
加密方案的选择可以看博客开始给的连接去选择。

/**
 * @description: 对请求数据进行加密处理
 * @author : yzq
 * @date   : 2019/3/16
 * @time   : 16:37
 *
 */

class RequestEncryptInterceptor : Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        var charset = Charset.forName("UTF-8")
        val method = request.method().toLowerCase().trim()

        val url = request.url()
        /*本次请求的接口地址*/
        val apiPath = "${url.scheme()}://${url.host()}:${url.port()}${url.encodedPath()}".trim()
        /*服务端的接口地址*/
        val serverPath = "${url.scheme()}://${url.host()}/".trim()
        /*如果请求的不是服务端的接口,不加密*/
        if (!serverPath.startsWith(ServerConstants.getServerUrl())) {
            return chain.proceed(request)
        }

        /*如果请求方式是Get或者Delete,此时请求数据是拼接在请求地址后面的*/
        if (method.equals("get") || method.equals("delete")) {

            /*如果有请求数据 则加密*/
            if (url.encodedQuery() != null) {
                try {
                    val queryparamNames = request.url().encodedQuery()
                    val encryptqueryparamNames=“这里调用加密的方法,自行修改”
             		//拼接加密后的url,参数字段自己跟后台商量,这里我用param,后台拿到数据先对param进行解密,解密后的数据就是请求的数据
                    val newUrl = "$apiPath?param=$encryptqueryparamNames"
                    //构建新的请求
                    request = request.newBuilder().url(newUrl ).build()
                } catch (e: Exception) {
                    e.printStackTrace()
                    return chain.proceed(request)
                }
            }
        } else {
        	//不是Get和Delete请求时,则请求数据在请求体中
            val requestBody = request.body()

            /*判断请求体是否为空  不为空则执行以下操作*/
            if (requestBody != null) {
                val contentType = requestBody.contentType()
                if (contentType != null) {
                    charset = contentType.charset(charset)
                    /*如果是二进制上传  则不进行加密*/
                    if (contentType.type().toLowerCase().equals("multipart")) {                     
                        return chain.proceed(request)
                    }
                }

                /*获取请求的数据*/
                try {
                    val buffer = Buffer()
                    requestBody.writeTo(buffer)
                    val requestData = URLDecoder.decode(buffer.readString(charset).trim(), "utf-8")

                 	val encryptData=“这里调用加密的方法,自行修改”
                    /*构建新的请求体*/
                    val newRequestBody = RequestBody.create(contentType, encryptData)

                    /*构建新的requestBuilder*/
                    val newRequestBuilder = request.newBuilder()
                    //根据请求方式构建相应的请求
                    when (method) {
                        "post" -> newRequestBuilder.post(newRequestBody)
                        "put" -> newRequestBuilder.put(newRequestBody)
                    }
                    request = newRequestBuilder.build()

                } catch (e: Exception) {
                    LogUtils.e("加密异常====》${e}")
                    return chain.proceed(request)
                }
            }
        }
        return chain.proceed(request)
    }
}

好了,加密拦截器基本就是这样


Retrofit 统一解密拦截器

解密就简单跟多了,直接处理相应体即可,下面是参考代码

/**
 * @description: 对响应数据进行解密
 * @author : yzq
 * @date   : 2019/3/20
 * @time   : 16:13
 *
 */

class ResponseDecryptInterceptor : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {

        val request = chain.request()
        var response = chain.proceed(request)

        if (response.isSuccessful) {
            val responseBody = response.body()
            if (esponseBody != null) {
                /*开始解密*/
                try {
                    val source = responseBody.source()
                    source.request(java.lang.Long.MAX_VALUE)
                    val buffer = source.buffer()
                    var charset = Charset.forName("UTF-8")
                    val contentType = responseBody.contentType()
                    if (contentType != null) {
                        charset = contentType.charset(charset)
                    }
                    val bodyString = buffer.clone().readString(charset)        
                    val responseData = “这里调解密的方法”                  
                    /*将解密后的明文返回*/
                    val newResponseBody = ResponseBody.create(contentType, responseData.trim())
                    response = response.newBuilder().body(newResponseBody).build()
                } catch (e: Exception) {
                    /*异常说明解密失败 信息被篡改 直接返回即可 */
                    LogUtils.e("解密异常====》${e}")
                    return response
                }
            } else {
                LogUtils.i("响应体为空")
            }
        }
        return response

    }
}

好了,解密拦截器就完成了。


加解密拦截器写好之后添加到okHttp中即可。

        val okHttpBuilder = OkHttpClient.Builder()
            .addInterceptor(RequestHeadersInterceptor())
            .addInterceptor(RequestEncryptInterceptor())
            .addInterceptor(initLogInterceptor())
            .addInterceptor(ResponseDecryptInterceptor())
            .build()

然后就可以和后台进行联调测试了。


如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

  • 12
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
这是一个比较大型的项目,需要多个模块的协作完成。以下是基本的步骤和代码实现: 1. 创建一个新项目,并添加以下依赖项到 app 模块的 build.gradle 文件中: ```groovy implementation 'com.google.android.material:material:1.2.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.github.bumptech.glide:glide:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' implementation 'com.airbnb.android:lottie:3.4.0' ``` 2. 在 res/layout 目录下创建布局文件 activity_main.xml,并添加以下代码: ```xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="4dp" android:theme="@style/ThemeOverlay.AppCompat.ActionBar" /> <TextView android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:text="Welcome to the Library Booking App!" android:textSize="24sp" /> </LinearLayout> ``` 3. 在 MainActivity 中添加以下代码: ```java public class MainActivity extends AppCompatActivity { private TextView textView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); textView = findViewById(R.id.text_view); } } ``` 4. 创建一个新的 Java 类 BookApi,并添加以下代码: ```java public interface BookApi { @GET("books") Call<List<Book>> getBooks(); @GET("book/{id}") Call<Book> getBook(@Path("id") int id); @POST("book") Call<Book> createBook(@Body Book book); @PUT("book/{id}") Call<Book> updateBook(@Path("id") int id, @Body Book book); @DELETE("book/{id}") Call<Void> deleteBook(@Path("id") int id); } ``` 5. 创建一个新的 Java 类 Book,并添加以下代码: ```java public class Book { private int id; private String title; private String author; private String coverUrl; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getCoverUrl() { return coverUrl; } public void setCoverUrl(String coverUrl) { this.coverUrl = coverUrl; } } ``` 6. 创建一个新的 Java 类 BookAdapter,并添加以下代码: ```java public class BookAdapter extends RecyclerView.Adapter<BookAdapter.ViewHolder> { private List<Book> books; private OnItemClickListener onItemClickListener; public void setBooks(List<Book> books) { this.books = books; notifyDataSetChanged(); } public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.onItemClickListener = onItemClickListener; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_book, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { Book book = books.get(position); holder.titleTextView.setText(book.getTitle()); holder.authorTextView.setText(book.getAuthor()); Glide.with(holder.coverImageView.getContext()) .load(book.getCoverUrl()) .into(holder.coverImageView); } @Override public int getItemCount() { return books != null ? books.size() : 0; } class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { ImageView coverImageView; TextView titleTextView; TextView authorTextView; ViewHolder(@NonNull View itemView) { super(itemView); coverImageView = itemView.findViewById(R.id.cover_image_view); titleTextView = itemView.findViewById(R.id.title_text_view); authorTextView = itemView.findViewById(R.id.author_text_view); itemView.setOnClickListener(this); } @Override public void onClick(View v) { if (onItemClickListener != null) { onItemClickListener.onItemClick(getAdapterPosition()); } } } public interface OnItemClickListener { void onItemClick(int position); } } ``` 7. 在 res/layout 目录下创建布局文件 item_book.xml,并添加以下代码: ```xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:orientation="horizontal"> <ImageView android:id="@+id/cover_image_view" android:layout_width="96dp" android:layout_height="128dp" android:scaleType="centerCrop" android:src="@drawable/ic_book" /> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_weight="1" android:orientation="vertical"> <TextView android:id="@+id/title_text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Book Title" android:textSize="18sp" /> <TextView android:id="@+id/author_text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Author" android:textSize="16sp" /> </LinearLayout> </LinearLayout> ``` 8. 修改 activity_main.xml 文件中的代码,将 TextView 替换为 RecyclerView,并添加以下代码: ```xml <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> ``` 9. 在 MainActivity 中添加以下代码: ```java public class MainActivity extends AppCompatActivity { private BookAdapter bookAdapter; private BookApi bookApi; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); bookAdapter = new BookAdapter(); bookAdapter.setOnItemClickListener(new BookAdapter.OnItemClickListener() { @Override public void onItemClick(int position) { // TODO: Handle item click event } }); recyclerView.setAdapter(bookAdapter); Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://your.api.url/") .addConverterFactory(GsonConverterFactory.create()) .build(); bookApi = retrofit.create(BookApi.class); loadBooks(); } private void loadBooks() { Call<List<Book>> call = bookApi.getBooks(); call.enqueue(new Callback<List<Book>>() { @Override public void onResponse(Call<List<Book>> call, Response<List<Book>> response) { if (response.isSuccessful()) { List<Book> books = response.body(); bookAdapter.setBooks(books); } else { // TODO: Handle error response } } @Override public void onFailure(Call<List<Book>> call, Throwable t) { // TODO: Handle network error } }); } } ``` 10. 运行应用程序,如果一切正常,您将看到图书列表。现在,您可以添加其他功能,例如图书详情页面、预订图书等。
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喻志强(Xeon)

码字不易,鼓励随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值