springmvc文件上傳AND jwt身份驗證

SpringMVC文件上傳

思路:
一、首先定義頁面,定義多功能表單(enctype=「multipart/form-data」)
二、在Controller裏面定義一個方法,用參數(MultipartFile)來接收前臺傳遞過來的文件對象
三、而後文件上傳就是把文件從一個地方(本地)複製到另一個地方(服務器)html

 

添加pom依賴

<dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
</dependency>

 

配置springservlet-mvc.xml

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 必須和用戶JSP 的pageEncoding屬性一致,以便正確解析表單的內容 -->
        <property name="defaultEncoding" value="UTF-8"></property>
        <!-- 文件最大大小(字節) 1024*1024*50=50M-->
        <property name="maxUploadSize" value="52428800"></property>
        <!--resolveLazily屬性啓用是爲了推遲文件解析,以便捕獲文件大小異常-->
        <property name="resolveLazily" value="true"/>
    </bean>

 

文件上傳的方法

 /**
     * 文件上傳的方法
     * @param req
     * @return
     */
    @RequestMapping("/upload")
    public String upload(HttpServletRequest req, MultipartFile xxx){
        String fileName = xxx.getOriginalFilename();
        String contentType = xxx.getContentType();
        try {
            FileUtils.copyInputStreamToFile(xxx.getInputStream(),new File("D:/xxx/"+fileName));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "redirect:/book/list";
    }

 

upload.jsp

<%--
  Created by IntelliJ IDEA.
  User: 源
  Date: 2019/10/30
  Time: 18:12
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>講解springmvc文件上傳</title>
</head>
<body>
<form action="/book/upload" method="post" enctype="multipart/form-data">
    請選擇文件:<input type="file" name="xxx" />
    <input type="submit" value="ok" />

</form>
</body>
</html>

 

上傳結果

經過瀏覽器進行訪問

 

 

 

Jwt實現登陸驗證

思路:
登陸界面向後臺請求驗證碼,後臺就先調用隨機函數生成驗證碼,而且根據驗證碼生成一張圖片,以 base64 字符串的形式傳到前臺,這時咱們還要生成verificationJwt令牌作爲請求驗證碼客戶端的區分。咱們先將驗證碼信息存入redis。key是 verificationJwt令牌的值,value就是驗證碼了。而且將令牌放入到響應頭。傳給客戶端。當客戶端提交的時候將保持的verificationJwt令牌放入請求頭帶過來。後端根據前端傳過來的 jwt令牌去redis中獲取數據,將驗證碼拿到後和現有的驗證碼進行比較。看看是否相等
細節:
訪問一次登陸頁面,生成一個verificationJwt令牌,這個令牌的有效時間是5min,驗證碼在redis中的有效時間是1min,不管是verificationJwt令牌超時失效,仍是驗證碼生成後超時失效,都會形成登陸失敗;
簡單來講就是跳轉到登錄界面,須要在5min中以內完成登陸,新的驗證碼出來後,須要在1min中以內完成登陸前端

 

導入pom依賴

<!--引入JWT依賴,因爲是基於Java,因此須要的是java-jwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.4.0</version>
        </dependency>

 

vue前端代碼

State.jsvue

export default {
  resturantName: '每天餐館',
  jwt:'',
  options: [],//存放tab頁的容器
    activeIndex: '',//激活的tab頁路由路徑
      showName:'show',//tab頁的標題
      role:""//用來區分是不是由於左側菜單被點擊形成的路由路徑發生改變,是:pass;不是:nopass
    verificationJwt:null, //這是用來保存用戶等登陸驗證碼jwt身份識別的
}

Mutations.jsjava

setVerificationJwt: (state, payload) => {
          state.verificationJwt = payload.verificationJwt;
      },

Getters.jsios

getVerificationJwt:(state) =>{
          return state.verificationJwt;
      },

action.jsweb

/**
 * 對後臺請求的地址的封裝,URL格式以下:
 * 模塊名_實體名_操做
 */
export default {
    // 'SERVER': 'http://localhost:8080/T216_SSH', //服務器
  'SERVER': 'http://localhost:8080', // /webDemo/ssm 服務器
  'SYSTEM_USER_DOLOGIN': '/vue/user/login', //用戶登錄
  'VERIFICATION': '/vue/user/verificationCode', //用戶登錄
    // 'SYSTEM_USER_DOLOGIN': '/vue/userAction_login.action', //用戶登錄
    // 'SYSTEM_USER_DOREG': '/vue/userAction_reg.action', //用戶註冊
    'SYSTEM_MENU_TREE': '/vue/treeNodeAction.action', //左側樹形菜單加載
    'SYSTEM_ARTICLE_LIST': '/vue/articleAction_list.action', //文章列表
    'SYSTEM_ARTICLE_ADD': '/vue/articleAction_add.action', //文章新增
    'SYSTEM_ARTICLE_EDIT': '/vue/articleAction_edit.action', //文章修改
    'SYSTEM_ARTICLE_DEL': '/vue/articleAction_del.action', //文章刪除
    'SYSTEM_USER_GETASYNCDATA': '/vue/userAction_getAsyncData.action', //vuex中的異步加載數據
    'getFullPath': k => { //得到請求的完整地址,用於mockjs測試時使用
        return this.SERVER + this[k];
    }
}

http.jsajax

 1 // 請求攔截器
 2 axios.interceptors.request.use(function(config) {
 3     //設置驗證碼jwt令牌
 4     let verificationJwt = window.vm.$store.getters.getVerificationJwt;
 5     if (verificationJwt) {
 6         config.headers['verificationJwt'] = verificationJwt;
 7     }
 8 
 9     var jwt = window.vm.$store.getters.getJwt;
10     config.headers['jwt'] = jwt;
11     return config;
12 }, function(error) {
13     return Promise.reject(error);
14 });
15 
16 // 響應攔截器
17 axios.interceptors.response.use(function(response) {
18     // debugger;
19     //保存驗證碼jwt令牌
20     let verificationjwt = response.headers['verificationjwt'];
21     if (verificationjwt) {
22         window.vm.$store.commit('setVerificationJwt', {
23             verificationJwt: verificationjwt
24         });
25     }
26     
27     var jwt = response.headers['jwt'];
28     if (jwt) {
29         window.vm.$store.commit('setJwt', {
30             jwt: jwt
31         });
32     }
33     return response;
34 }, function(error) {
35     return Promise.reject(error);
36 });

 

登陸界面login.vueredis

  1 <template>
  2   <div class="login-wrap">
  3     <el-form class="login-container">
  4       <h1 class="title">用戶登陸</h1>
  5       <el-form-item label="">
  6         <el-input type="text" v-model="userName" placeholder="請輸入登陸帳號" autocomplete="off"></el-input>
  7       </el-form-item>
  8       <el-form-item label="">
  9         <el-input type="password" v-model="userPwd" placeholder="請輸入登陸密碼" autocomplete="off"></el-input>
 10       </el-form-item>
 11       <el-form-item label="">
 12         <el-row>
 13           <el-col :span="16">
 14             <el-input type="text" v-model="verificationCode" placeholder="請輸入驗證碼" autocomplete="off"></el-input>
 15           </el-col>
 16           <el-col :span="8">
 17             <img id="img" :src="verificationCodeSrc" width="116px" height="40px" @click="changeVerificationCode" >
 18           </el-col>
 19         </el-row>
 20       </el-form-item>
 21       <el-form-item>
 22         <el-button type="primary" style="width: 100%;" @click="doSubmit">登  錄</el-button>
 23       </el-form-item>
 24       <el-row style="text-align: center; margin-top: -15;">
 25         <el-link type="primary">忘記密碼</el-link>
 26         <el-link type="primary" @click="gotoRegister">用戶註冊</el-link>
 27       </el-row>
 28     </el-form>
 29   </div>
 30 </template>
 31 
 32 
 33 <script>
 34     export default {
 35         name: 'Login',
 36         data: function() {
 37             return {
 38                 userName: null,
 39                 userPwd: null,
 40                 verificationCode:null,
 41                 verificationCodeSrc:null
 42             }
 43         },
 44         methods: {
 45             gotoRegister:function(){
 46                 this.$router.push('/Register');
 47             },
 48             doSubmit: function() {
 49                 let params = {
 50                     uname: this.userName,
 51                     pwd: this.userPwd,
 52                     verificationCode: this.verificationCode
 53                 };
 54                 let url = this.axios.urls.SYSTEM_USER_DOLOGIN;
 55 
 56                 this.axios.post(url, params).then(resp => {
 57                     if(resp.data.status==200) {
 58                         //提示登陸成功
 59                         this.$message({
 60                             message: resp.data.msg,
 61                             type: 'success'
 62                         });
 63                         //跳轉路由
 64                         this.$router.push({
 65                             path:'/Main'
 66                         })
 67                         //這是將用戶信息保持下來
 68 //                         let user=resp.data.data
 69 //                         this.$store.dispatch('setUserAsync',{
 70 //                             user:user
 71 //                         });
 72                     }else{
 73                         this.$message({
 74                             message: resp.data.msg,
 75                             type: 'error'
 76                         });
 77                     }
 78                 }).catch(resp => {
 79                     this.$message({
 80                         message: "請求異常",
 81                         type: 'error'
 82                     });
 83                 });
 84             },
 85             //更新驗證碼
 86             changeVerificationCode(){
 87                 let url = this.axios.urls.VERIFICATION;
 88                 this.axios.post(url, {}).then(resp => {
 89                     this.verificationCodeSrc = resp.data;
 90                 }).catch(resp => {
 91                     console.log(resp);
 92                 });
 93 
 94             }
 95         }
 96         ,
 97         created() {
 98             let url = this.axios.urls.VERIFICATION;
 99             this.axios.post(url, {}).then(resp => {
100                 this.verificationCodeSrc = resp.data;
101             }).catch(resp => {
102                 console.log(resp);
103             });
104         }
105     }
106 </script>
107 
108 <!-- Add "scoped" attribute to limit CSS to this component only -->
109 <style scoped>
110   .login-wrap {
111     box-sizing: border-box;
112     width: 100%;
113     height: 100%;
114     padding-top: 10%;
115     background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjEzNjFweCIgaGVpZ2h0PSI2MDlweCIgdmlld0JveD0iMCAwIDEzNjEgNjA5IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPCEtLSBHZW5lcmF0b3I6IFNrZXRjaCA0Ni4yICg0NDQ5NikgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+R3JvdXAgMjE8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz48L2RlZnM+CiAgICA8ZyBpZD0iQW50LURlc2lnbi1Qcm8tMy4wIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0i6LSm5oi35a+G56CB55m75b2VLeagoemqjCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTc5LjAwMDAwMCwgLTgyLjAwMDAwMCkiPgogICAgICAgICAgICA8ZyBpZD0iR3JvdXAtMjEiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDc3LjAwMDAwMCwgNzMuMDAwMDAwKSI+CiAgICAgICAgICAgICAgICA8ZyBpZD0iR3JvdXAtMTgiIG9wYWNpdHk9IjAuOCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzQuOTAxNDE2LCA1NjkuNjk5MTU4KSByb3RhdGUoLTcuMDAwMDAwKSB0cmFuc2xhdGUoLTc0LjkwMTQxNiwgLTU2OS42OTkxNTgpIHRyYW5zbGF0ZSg0LjkwMTQxNiwgNTI1LjE5OTE1OCkiPgogICAgICAgICAgICAgICAgICAgIDxlbGxpcHNlIGlkPSJPdmFsLTExIiBmaWxsPSIjQ0ZEQUU2IiBvcGFjaXR5PSIwLjI1IiBjeD0iNjMuNTc0ODc5MiIgY3k9IjMyLjQ2ODM2NyIgcng9IjIxLjc4MzA0NzkiIHJ5PSIyMS43NjYwMDgiPjwvZWxsaXBzZT4KICAgICAgICAgICAgICAgICAgICA8ZWxsaXBzZSBpZD0iT3ZhbC0zIiBmaWxsPSIjQ0ZEQUU2IiBvcGFjaXR5PSIwLjU5OTk5OTk2NCIgY3g9IjUuOTg3NDY0NzkiIGN5PSIxMy44NjY4NjAxIiByeD0iNS4yMTczOTEzIiByeT0iNS4yMTMzMDk5NyI+PC9lbGxpcHNlPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0zOC4xMzU0NTE0LDg4LjM1MjAyMTUgQzQzLjg5ODQyMjcsODguMzUyMDIxNSA0OC41NzAyMzQsODMuNjgzODY0NyA0OC41NzAyMzQsNzcuOTI1NDAxNSBDNDguNTcwMjM0LDcyLjE2NjkzODMgNDMuODk4NDIyNyw2Ny40OTg3ODE2IDM4LjEzNTQ1MTQsNjcuNDk4NzgxNiBDMzIuMzcyNDgwMSw2Ny40OTg3ODE2IDI3LjcwMDY2ODgsNzIuMTY2OTM4MyAyNy43MDA2Njg4LDc3LjkyNTQwMTUgQzI3LjcwMDY2ODgsODMuNjgzODY0NyAzMi4zNzI0ODAxLDg4LjM1MjAyMTUgMzguMTM1NDUxNCw4OC4zNTIwMjE1IFoiIGlkPSJPdmFsLTMtQ29weSIgZmlsbD0iI0NGREFFNiIgb3BhY2l0eT0iMC40NSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02NC4yNzc1NTgyLDMzLjE3MDQ5NjMgTDExOS4xODU4MzYsMTYuNTY1NDkxNSIgaWQ9IlBhdGgtMTIiIHN0cm9rZT0iI0NGREFFNiIgc3Ryb2tlLXdpZHRoPSIxLjczOTEzMDQzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNDIuMTQzMTcwOCwyNi41MDAyNjgxIEw3LjcxMTkwMTYyLDE0LjU2NDA3MDIiIGlkPSJQYXRoLTE2IiBzdHJva2U9IiNFMEI0QjciIHN0cm9rZS13aWR0aD0iMC43MDI2Nzg5NjQiIG9wYWNpdHk9IjAuNyIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtZGFzaGFycmF5PSIxLjQwNTM1Nzg5OTg3MzE1MywyLjEwODAzNjk1MzQ2OTk4MSI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik02My45MjYyMTg3LDMzLjUyMTU2MSBMNDMuNjcyMTMyNiw2OS4zMjUwOTUxIiBpZD0iUGF0aC0xNSIgc3Ryb2tlPSIjQkFDQUQ5IiBzdHJva2Utd2lkdGg9IjAuNzAyNjc4OTY0IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIHN0cm9rZS1kYXNoYXJyYXk9IjEuNDA1MzU3ODk5ODczMTUzLDIuMTA4MDM2OTUzNDY5OTgxIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwLTE3IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMjYuODUwOTIyLCAxMy41NDM2NTQpIHJvdGF0ZSgzMC4wMDAwMDApIHRyYW5zbGF0ZSgtMTI2Ljg1MDkyMiwgLTEzLjU0MzY1NCkgdHJhbnNsYXRlKDExNy4yODU3MDUsIDQuMzgxODg5KSIgZmlsbD0iI0NGREFFNiI+CiAgICAgICAgICAgICAgICAgICAgICAgIDxlbGxpcHNlIGlkPSJPdmFsLTQiIG9wYWNpdHk9IjAuNDUiIGN4PSI5LjEzNDgyNjUzIiBjeT0iOS4xMjc2ODA3NiIgcng9IjkuMTM0ODI2NTMiIHJ5PSI5LjEyNzY4MDc2Ij48L2VsbGlwc2U+CiAgICAgICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xOC4yNjk2NTMxLDE4LjI1NTM2MTUgQzE4LjI2OTY1MzEsMTMuMjE0MjgyNiAxNC4xNzk4NTE5LDkuMTI3NjgwNzYgOS4xMzQ4MjY1Myw5LjEyNzY4MDc2IEM0LjA4OTgwMTE0LDkuMTI3NjgwNzYgMCwxMy4yMTQyODI2IDAsMTguMjU1MzYxNSBMMTguMjY5NjUzMSwxOC4yNTUzNjE1IFoiIGlkPSJPdmFsLTQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDkuMTM0ODI3LCAxMy42OTE1MjEpIHNjYWxlKC0xLCAtMSkgdHJhbnNsYXRlKC05LjEzNDgyNywgLTEzLjY5MTUyMSkgIj48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwLTE0IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyMTYuMjk0NzAwLCAxMjMuNzI1NjAwKSByb3RhdGUoLTUuMDAwMDAwKSB0cmFuc2xhdGUoLTIxNi4yOTQ3MDAsIC0xMjMuNzI1NjAwKSB0cmFuc2xhdGUoMTA2LjI5NDcwMCwgMzUuMjI1NjAwKSI+CiAgICAgICAgICAgICAgICAgICAgPGVsbGlwc2UgaWQ9Ik92YWwtMiIgZmlsbD0iI0NGREFFNiIgb3BhY2l0eT0iMC4yNSIgY3g9IjI5LjExNzY0NzEiIGN5PSIyOS4xNDAyNDM5IiByeD0iMjkuMTE3NjQ3MSIgcnk9IjI5LjE0MDI0MzkiPjwvZWxsaXBzZT4KICAgICAgICAgICAgICAgICAgICA8ZWxsaXBzZSBpZD0iT3ZhbC0yIiBmaWxsPSIjQ0ZEQUU2IiBvcGFjaXR5PSIwLjMiIGN4PSIyOS4xMTc2NDcxIiBjeT0iMjkuMTQwMjQzOSIgcng9IjIxLjU2ODYyNzUiIHJ5PSIyMS41ODUzNjU5Ij48L2VsbGlwc2U+CiAgICAgICAgICAgICAgICAgICAgPGVsbGlwc2UgaWQ9Ik92YWwtMi1Db3B5IiBzdHJva2U9IiNDRkRBRTYiIG9wYWNpdHk9IjAuNCIgY3g9IjE3OS4wMTk2MDgiIGN5PSIxMzguMTQ2MzQxIiByeD0iMjMuNzI1NDkwMiIgcnk9IjIzLjc0MzkwMjQiPjwvZWxsaXBzZT4KICAgICAgICAgICAgICAgICAgICA8ZWxsaXBzZSBpZD0iT3ZhbC0yIiBmaWxsPSIjQkFDQUQ5IiBvcGFjaXR5PSIwLjUiIGN4PSIyOS4xMTc2NDcxIiBjeT0iMjkuMTQwMjQzOSIgcng9IjEwLjc4NDMxMzciIHJ5PSIxMC43OTI2ODI5Ij48L2VsbGlwc2U+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTI5LjExNzY0NzEsMzkuOTMyOTI2OCBMMjkuMTE3NjQ3MSwxOC4zNDc1NjEgQzIzLjE2MTYzNTEsMTguMzQ3NTYxIDE4LjMzMzMzMzMsMjMuMTc5NjA5NyAxOC4zMzMzMzMzLDI5LjE0MDI0MzkgQzE4LjMzMzMzMzMsMzUuMTAwODc4MSAyMy4xNjE2MzUxLDM5LjkzMjkyNjggMjkuMTE3NjQ3MSwzOS45MzI5MjY4IFoiIGlkPSJPdmFsLTIiIGZpbGw9IiNCQUNBRDkiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8ZyBpZD0iR3JvdXAtOSIgb3BhY2l0eT0iMC40NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTcyLjAwMDAwMCwgMTMxLjAwMDAwMCkiIGZpbGw9IiNFNkExQTYiPgogICAgICAgICAgICAgICAgICAgICAgICA8ZWxsaXBzZSBpZD0iT3ZhbC0yLUNvcHktMiIgY3g9IjcuMDE5NjA3ODQiIGN5PSI3LjE0NjM0MTQ2IiByeD0iNi40NzA1ODgyNCIgcnk9IjYuNDc1NjA5NzYiPjwvZWxsaXBzZT4KICAgICAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTAuNTQ5MDE5NjA4LDEzLjYyMTk1MTIgQzQuMTIyNjI2ODEsMTMuNjIxOTUxMiA3LjAxOTYwNzg0LDEwLjcyMjcyMiA3LjAxOTYwNzg0LDcuMTQ2MzQxNDYgQzcuMDE5NjA3ODQsMy41Njk5NjA5NSA0LjEyMjYyNjgxLDAuNjcwNzMxNzA3IDAuNTQ5MDE5NjA4LDAuNjcwNzMxNzA3IEwwLjU0OTAxOTYwOCwxMy42MjE5NTEyIFoiIGlkPSJPdmFsLTItQ29weS0yIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzLjc4NDMxNCwgNy4xNDYzNDEpIHNjYWxlKC0xLCAxKSB0cmFuc2xhdGUoLTMuNzg0MzE0LCAtNy4xNDYzNDEpICI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgICAgICA8ZWxsaXBzZSBpZD0iT3ZhbC0xMCIgZmlsbD0iI0NGREFFNiIgY3g9IjIxOC4zODIzNTMiIGN5PSIxMzguNjg1OTc2IiByeD0iMS42MTc2NDcwNiIgcnk9IjEuNjE4OTAyNDQiPjwvZWxsaXBzZT4KICAgICAgICAgICAgICAgICAgICA8ZWxsaXBzZSBpZD0iT3ZhbC0xMC1Db3B5LTIiIGZpbGw9IiNFMEI0QjciIG9wYWNpdHk9IjAuMzUiIGN4PSIxNzkuNTU4ODI0IiBjeT0iMTc1LjM4MTA5OCIgcng9IjEuNjE3NjQ3MDYiIHJ5PSIxLjYxODkwMjQ0Ij48L2VsbGlwc2U+CiAgICAgICAgICAgICAgICAgICAgPGVsbGlwc2UgaWQ9Ik92YWwtMTAtQ29weSIgZmlsbD0iI0UwQjRCNyIgb3BhY2l0eT0iMC4zNSIgY3g9IjE4MC4wOTgwMzkiIGN5PSIxMDIuNTMwNDg4IiByeD0iMi4xNTY4NjI3NSIgcnk9IjIuMTU4NTM2NTkiPjwvZWxsaXBzZT4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMjguOTk4NTM4MSwyOS45NjcxNTk4IEwxNzEuMTUxMDE4LDEzMi44NzYwMjQiIGlkPSJQYXRoLTExIiBzdHJva2U9IiNDRkRBRTYiIG9wYWNpdHk9IjAuOCI+PC9wYXRoPgogICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwLTEwIiBvcGFjaXR5PSIwLjc5OTk5OTk1MiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTA1NC4xMDA2MzUsIDM2LjY1OTMxNykgcm90YXRlKC0xMS4wMDAwMDApIHRyYW5zbGF0ZSgtMTA1NC4xMDA2MzUsIC0zNi42NTkzMTcpIHRyYW5zbGF0ZSgxMDI2LjYwMDYzNSwgNC42NTkzMTcpIj4KICAgICAgICAgICAgICAgICAgICA8ZWxsaXBzZSBpZD0iT3ZhbC03IiBzdHJva2U9IiNDRkRBRTYiIHN0cm9rZS13aWR0aD0iMC45NDExNzY0NzEiIGN4PSI0My44MTM1NTkzIiBjeT0iMzIiIHJ4PSIxMS4xODY0NDA3IiByeT0iMTEuMjk0MTE3NiI+PC9lbGxpcHNlPgogICAgICAgICAgICAgICAgICAgIDxnIGlkPSJHcm91cC0xMiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMzQuNTk2Nzc0LCAyMy4xMTExMTEpIiBmaWxsPSIjQkFDQUQ5Ij4KICAgICAgICAgICAgICAgICAgICAgICAgPGVsbGlwc2UgaWQ9Ik92YWwtNyIgb3BhY2l0eT0iMC40NSIgY3g9IjkuMTg1MzQ3MTgiIGN5PSI4Ljg4ODg4ODg5IiByeD0iOC40NzQ1NzYyNyIgcnk9IjguNTU2MTQ5NzMiPjwvZWxsaXBzZT4KICAgICAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTkuMTg1MzQ3MTgsMTcuNDQ1MDM4NiBDMTMuODY1NzI2NCwxNy40NDUwMzg2IDE3LjY1OTkyMzUsMTMuNjE0MzE5OSAxNy42NTk5MjM1LDguODg4ODg4ODkgQzE3LjY1OTkyMzUsNC4xNjM0NTc4NyAxMy44NjU3MjY0LDAuMzMyNzM5MTU2IDkuMTg1MzQ3MTgsMC4zMzI3MzkxNTYgTDkuMTg1MzQ3MTgsMTcuNDQ1MDM4NiBaIiBpZD0iT3ZhbC03Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPC9nPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0zNC42NTk3Mzg1LDI0LjgwOTY5NCBMNS43MTY2NjA4NCw0Ljc2ODc4OTQ1IiBpZD0iUGF0aC0yIiBzdHJva2U9IiNDRkRBRTYiIHN0cm9rZS13aWR0aD0iMC45NDExNzY0NzEiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8ZWxsaXBzZSBpZD0iT3ZhbCIgc3Ryb2tlPSIjQ0ZEQUU2IiBzdHJva2Utd2lkdGg9IjAuOTQxMTc2NDcxIiBjeD0iMy4yNjI3MTE4NiIgY3k9IjMuMjk0MTE3NjUiIHJ4PSIzLjI2MjcxMTg2IiByeT0iMy4yOTQxMTc2NSI+PC9lbGxpcHNlPgogICAgICAgICAgICAgICAgICAgIDxlbGxpcHNlIGlkPSJPdmFsLUNvcHkiIGZpbGw9IiNGN0UxQUQiIGN4PSIyLjc5NjYxMDE3IiBjeT0iNjEuMTc2NDcwNiIgcng9IjIuNzk2NjEwMTciIHJ5PSIyLjgyMzUyOTQxIj48L2VsbGlwc2U+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTM0LjYzMTI0NDMsMzkuMjkyMjcxMiBMNS4wNjM2NjY2Myw1OS43ODUwODIiIGlkPSJQYXRoLTEwIiBzdHJva2U9IiNDRkRBRTYiIHN0cm9rZS13aWR0aD0iMC45NDExNzY0NzEiPjwvcGF0aD4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgICAgIDxnIGlkPSJHcm91cC0xOSIgb3BhY2l0eT0iMC4zMyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI4Mi41MzcyMTksIDQ0Ni41MDI4NjcpIHJvdGF0ZSgtMTAuMDAwMDAwKSB0cmFuc2xhdGUoLTEyODIuNTM3MjE5LCAtNDQ2LjUwMjg2NykgdHJhbnNsYXRlKDExNDIuNTM3MjE5LCAzMjcuNTAyODY3KSI+CiAgICAgICAgICAgICAgICAgICAgPGcgaWQ9Ikdyb3VwLTE3IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNDEuMzMzNTM5LCAxMDQuNTAyNzQyKSByb3RhdGUoMjc1LjAwMDAwMCkgdHJhbnNsYXRlKC0xNDEuMzMzNTM5LCAtMTA0LjUwMjc0MikgdHJhbnNsYXRlKDEyOS4zMzM1MzksIDkyLjUwMjc0MikiIGZpbGw9IiNCQUNBRDkiPgogICAgICAgICAgICAgICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsLTQiIG9wYWNpdHk9IjAuNDUiIGN4PSIxMS42NjY2NjY3IiBjeT0iMTEuNjY2NjY2NyIgcj0iMTEuNjY2NjY2NyI+PC9jaXJjbGU+CiAgICAgICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMy4zMzMzMzMzLDIzLjMzMzMzMzMgQzIzLjMzMzMzMzMsMTYuODkwMDExMyAxOC4xMDk5ODg3LDExLjY2NjY2NjcgMTEuNjY2NjY2NywxMS42NjY2NjY3IEM1LjIyMzM0NDU5LDExLjY2NjY2NjcgMCwxNi44OTAwMTEzIDAsMjMuMzMzMzMzMyBMMjMuMzMzMzMzMywyMy4zMzMzMzMzIFoiIGlkPSJPdmFsLTQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDExLjY2NjY2NywgMTcuNTAwMDAwKSBzY2FsZSgtMSwgLTEpIHRyYW5zbGF0ZSgtMTEuNjY2NjY3LCAtMTcuNTAwMDAwKSAiPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC01LUNvcHktNiIgZmlsbD0iI0NGREFFNiIgY3g9IjIwMS44MzMzMzMiIGN5PSI4Ny41IiByPSI1LjgzMzMzMzMzIj48L2NpcmNsZT4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTQzLjUsODguODEyNjY4NSBMMTU1LjA3MDUwMSwxNy42MDM4NTQ0IiBpZD0iUGF0aC0xNyIgc3Ryb2tlPSIjQkFDQUQ5IiBzdHJva2Utd2lkdGg9IjEuMTY2NjY2NjciPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMTcuNSwzNy4zMzMzMzMzIEwxMjcuNDY2MjUyLDk3LjY0NDk3MzUiIGlkPSJQYXRoLTE4IiBzdHJva2U9IiNCQUNBRDkiIHN0cm9rZS13aWR0aD0iMS4xNjY2NjY2NyI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxwb2x5bGluZSBpZD0iUGF0aC0xOSIgc3Ryb2tlPSIjQ0ZEQUU2IiBzdHJva2Utd2lkdGg9IjEuMTY2NjY2NjciIHBvaW50cz0iMTQzLjkwMjU5NyAxMjAuMzAyMjgxIDE3NC45MzU0NTUgMjMxLjU3MTM0MiAzOC41IDE0Ny41MTA4NDcgMTI2LjM2Njk0MSAxMTAuODMzMzMzIj48L3BvbHlsaW5lPgogICAgICAgICAgICAgICAgICAgIDxwYXRoIGQ9Ik0xNTkuODMzMzMzLDk5Ljc0NTM4NDIgTDE5NS40MTY2NjcsODkuMjUiIGlkPSJQYXRoLTIwIiBzdHJva2U9IiNFMEI0QjciIHN0cm9rZS13aWR0aD0iMS4xNjY2NjY2NyIgb3BhY2l0eT0iMC42Ij48L3BhdGg+CiAgICAgICAgICAgICAgICAgICAgPHBhdGggZD0iTTIwNS4zMzMzMzMsODIuMTM3MjEwNSBMMjM4LjcxOTQwNiwzNi4xNjY2NjY3IiBpZD0iUGF0aC0yNCIgc3Ryb2tlPSIjQkFDQUQ5IiBzdHJva2Utd2lkdGg9IjEuMTY2NjY2NjciPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNMjY2LjcyMzQyNCwxMzIuMjMxOTg4IEwyMDcuMDgzMzMzLDkwLjQxNjY2NjciIGlkPSJQYXRoLTI1IiBzdHJva2U9IiNDRkRBRTYiIHN0cm9rZS13aWR0aD0iMS4xNjY2NjY2NyI+PC9wYXRoPgogICAgICAgICAgICAgICAgICAgIDxjaXJjbGUgaWQ9Ik92YWwtNSIgZmlsbD0iI0MxRDFFMCIgY3g9IjE1Ni45MTY2NjciIGN5PSI4Ljc1IiByPSI4Ljc1Ij48L2NpcmNsZT4KICAgICAgICAgICAgICAgICAgICA8Y2lyY2xlIGlkPSJPdmFsLTUtQ29weS0zIiBmaWxsPSIjQzFEMUUwIiBjeD0iMzkuMDgzMzMzMyIgY3k9IjE0OC43NSIgcj0iNS4yNSI+PC9jaXJjbGU+CiAgICAgICAgICAgICAgICAgICAgPGNpcmNsZSBpZD0iT3ZhbC01LUNvcHktMiIgZmlsbC1vcGFjaXR5PSIwLjYiIGZpbGw9IiNEMURFRUQiIGN4PSI4Ljc1IiBjeT0iMzMuMjUiIHI9IjguNzUiPjwvY2lyY2xlPgogICAgICAgICAgICAgICAgICAgIDxjaXJjbGUgaWQ9Ik92YWwtNS1Db3B5LTQiIGZpbGwtb3BhY2l0eT0iMC42IiBmaWxsPSIjRDFERUVEIiBjeD0iMjQzLjgzMzMzMyIgY3k9IjMwLjMzMzMzMzMiIHI9IjUuODMzMzMzMzMiPjwvY2lyY2xlPgogICAgICAgICAgICAgICAgICAgIDxjaXJjbGUgaWQ9Ik92YWwtNS1Db3B5LTUiIGZpbGw9IiNFMEI0QjciIGN4PSIxNzUuNTgzMzMzIiBjeT0iMjMyLjc1IiByPSI1LjI1Ij48L2NpcmNsZT4KICAgICAgICAgICAgICAgIDwvZz4KICAgICAgICAgICAgPC9nPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+);
116     /* background-color: #112346; */
117     background-repeat: no-repeat;
118     background-position: center right;
119     background-size: 100%;
120   }
121 
122   .login-container {
123     border-radius: 10px;
124     margin: 0px auto;
125     width: 350px;
126     padding: 30px 35px 15px 35px;
127     background: #fff;
128     border: 1px solid #eaeaea;
129     text-align: left;
130     box-shadow: 0 0 20px 2px rgba(0, 0, 0, 0.1);
131   }
132 
133   .title {
134     margin: 0px auto 40px auto;
135     text-align: center;
136     color: #505458;
137   }
138 </style>

 

 

後端代碼

Util類

CorsFilter算法

 1 package com.yuan.util;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.Filter;
 6 import javax.servlet.FilterChain;
 7 import javax.servlet.FilterConfig;
 8 import javax.servlet.ServletException;
 9 import javax.servlet.ServletRequest;
10 import javax.servlet.ServletResponse;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13 
14 /**
15  * 配置tomcat容許跨域訪問
16  *
17  * @author Administrator
18  *
19  */
20 public class CorsFilter implements Filter {
21 
22     @Override
23     public void init(FilterConfig filterConfig) throws ServletException {
24     }
25 
26     @Override
27     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
28             throws IOException, ServletException {
29         HttpServletResponse resp = (HttpServletResponse) servletResponse;
30         HttpServletRequest req = (HttpServletRequest) servletRequest;
31 
32         // Access-Control-Allow-Origin就是咱們須要設置的域名
33         // Access-Control-Allow-Headers跨域容許包含的頭。
34         // Access-Control-Allow-Methods是容許的請求方式
35         resp.setHeader("Access-Control-Allow-Origin", "*");// *,任何域名
36         resp.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE");
37         // resp.setHeader("Access-Control-Allow-Headers", "Origin,X-Requested-With,
38         // Content-Type, Accept");
39         // 容許客戶端,發一個新的請求頭jwt
40         //容許客戶端發送一個新的請求頭
41         resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, jwt, verificationJwt");
42         //容許客戶端處理一個新的響應頭jwt
43         resp.setHeader("Access-Control-Expose-Headers", "jwt");
44         resp.setHeader("Access-Control-Expose-Headers", "verificationJwt");
45         // String sss = resp.getHeader("Access-Control-Expose-Headers");
46         // System.out.println("sss=" + sss);
47 
48         // 容許請求頭Token
49         // httpResponse.setHeader("Access-Control-Allow-Headers","Origin,X-Requested-With,
50         // Content-Type, Accept, Token");
51         // System.out.println("Token=" + req.getHeader("Token"));
52 
53         if ("OPTIONS".equals(req.getMethod())) {// axios的ajax會發兩次請求,第一次提交方式爲:option,直接返回便可
54             return;
55         }
56         filterChain.doFilter(servletRequest, servletResponse);
57     }
58 
59     @Override
60     public void destroy() {
61 
62     }
63 }

ImageUtilspring

 1 package com.yuan.util;
 2 
 3 import sun.misc.BASE64Encoder;
 4 
 5 import javax.imageio.ImageIO;
 6 import java.awt.*;
 7 import java.awt.image.BufferedImage;
 8 import java.io.ByteArrayOutputStream;
 9 import java.io.IOException;
10 import java.util.Random;
11 
12 public class ImageUtil {
13 
14     /**
15      * 根據指定的隨機數 生成驗證碼圖片 轉 base64
16      * @param word 要生存的驗證碼隨機字符串
17      * @param width 圖片寬度
18      * @param height 圖片高度
19      * @return base64 格式生成的驗證碼圖片
20      * @throws IOException
21      */
22     public static String createImageWithVerifyCode(String word, int width, int height) throws IOException {
23         String png_base64="";
24         //繪製內存中的圖片
25         BufferedImage bufferedImage = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
26         //獲得畫圖對象
27         Graphics graphics = bufferedImage.getGraphics();
28         //繪製圖片前指定一個顏色
29         graphics.setColor(getRandColor(160,200));
30         graphics.fillRect(0,0,width,height);
31         //繪製邊框
32         graphics.setColor(Color.white);
33         graphics.drawRect(0, 0, width - 1, height - 1);
34         // 步驟四 四個隨機數字
35         Graphics2D graphics2d = (Graphics2D) graphics;
36         graphics2d.setFont(new Font("宋體", Font.BOLD, 18));
37         Random random = new Random();
38         // 定義x座標
39         int x = 10;
40         for (int i = 0; i < word.length(); i++) {
41             // 隨機顏色
42             graphics2d.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
43             // 旋轉 -30 --- 30度
44             int jiaodu = random.nextInt(60) - 30;
45             // 換算弧度
46             double theta = jiaodu * Math.PI / 180;
47             // 得到字母數字
48             char c = word.charAt(i);
49             //將c 輸出到圖片
50             graphics2d.rotate(theta, x, 20);
51             graphics2d.drawString(String.valueOf(c), x, 20);
52             graphics2d.rotate(-theta, x, 20);
53             x += 30;
54         }
55         // 繪製干擾線
56         graphics.setColor(getRandColor(160, 200));
57         int x1;
58         int x2;
59         int y1;
60         int y2;
61         for (int i = 0; i < 30; i++) {
62             x1 = random.nextInt(width);
63             x2 = random.nextInt(12);
64             y1 = random.nextInt(height);
65             y2 = random.nextInt(12);
66             graphics.drawLine(x1, y1, x1 + x2, x2 + y2);
67         }
68         graphics.dispose();// 釋放資源
69         ByteArrayOutputStream baos = new ByteArrayOutputStream();//io流
70         ImageIO.write(bufferedImage, "png", baos);//寫入流中
71         byte[] bytes = baos.toByteArray();//轉換成字節
72         BASE64Encoder encoder = new BASE64Encoder();
73         png_base64 = encoder.encodeBuffer(bytes).trim();
74         png_base64 = png_base64.replaceAll("\n", "").replaceAll("\r", "");//刪除 \r\n
75         return png_base64;
76     }
77 
78 
79 
80     /**設置隨機顏色*/
81     private static Color getRandColor(int fc, int bc) {
82         // 取其隨機顏色
83         Random random = new Random();
84         if (fc > 255) {
85             fc = 255;
86         }
87         if (bc > 255) {
88             bc = 255;
89         }
90         int r = fc + random.nextInt(bc - fc);
91         int g = fc + random.nextInt(bc - fc);
92         int b = fc + random.nextInt(bc - fc);
93         return new Color(r, g, b);
94     }
95 
96 }

JSONResult

 1 package com.yuan.util;
 2 
 3 public class JSONResult {
 4 
 5     // 響應業務狀態
 6     private Integer status;
 7 
 8     // 響應消息
 9     private String msg;
10 
11     // 響應中的數據
12     private Object data;
13     
14     private String ok; // 不使用
15 
16     public static JSONResult build(Integer status, String msg, Object data) {
17         return new JSONResult(status, msg, data);
18     }
19 
20     public static JSONResult ok(Object data) {
21         return new JSONResult(data);
22     }
23 
24     public static JSONResult ok() {
25         return new JSONResult(null);
26     }
27     
28     public static JSONResult errorMsg(String msg) {
29         return new JSONResult(500, msg, null);
30     }
31     
32     public static JSONResult errorMap(Object data) {
33         return new JSONResult(501, "error", data);
34     }
35     
36     public static JSONResult errorTokenMsg(String msg) {
37         return new JSONResult(502, msg, null);
38     }
39     
40     public static JSONResult errorException(String msg) {
41         return new JSONResult(555, msg, null);
42     }
43 
44     public JSONResult() {
45 
46     }
47 
48     public JSONResult(Integer status, String msg, Object data) {
49         this.status = status;
50         this.msg = msg;
51         this.data = data;
52     }
53 
54     public JSONResult(Object data) {
55         this.status = 200;
56         this.msg = "OK";
57         this.data = data;
58     }
59 
60     public Boolean isOK() {
61         return this.status == 200;
62     }
63 
64     public Integer getStatus() {
65         return status;
66     }
67 
68     public void setStatus(Integer status) {
69         this.status = status;
70     }
71 
72     public String getMsg() {
73         return msg;
74     }
75 
76     public void setMsg(String msg) {
77         this.msg = msg;
78     }
79 
80     public Object getData() {
81         return data;
82     }
83 
84     public void setData(Object data) {
85         this.data = data;
86     }
87 
88    public String getOk() {
89       return ok;
90    }
91 
92    public void setOk(String ok) {
93       this.ok = ok;
94    }
95 
96 }

JwtUtils

  1 package com.yuan.util;
  2 
  3 import java.util.Date;
  4 import java.util.Map;
  5 import java.util.UUID;
  6 
  7 import javax.crypto.SecretKey;
  8 import javax.crypto.spec.SecretKeySpec;
  9 
 10 import org.apache.commons.codec.binary.Base64;
 11 
 12 import io.jsonwebtoken.Claims;
 13 import io.jsonwebtoken.JwtBuilder;
 14 import io.jsonwebtoken.Jwts;
 15 import io.jsonwebtoken.SignatureAlgorithm;
 16 
 17 /**
 18  * JWT驗證過濾器:配置順序 CorsFilte->JwtUtilsr-->StrutsPrepareAndExecuteFilter
 19  *
 20  */
 21 public class JwtUtils {
 22    /**
 23     * JWT_WEB_TTL:WEBAPP應用中token的有效時間,默認30分鐘
 24     */
 25    public static final long JWT_WEB_TTL = 5 * 60 * 1000;
 26 
 27    /**
 28     * 將jwt令牌保存到header中的key
 29     */
 30    public static final String JWT_HEADER_KEY = "jwt";
 31    public static final String JWT_VERIFICATION_KEY = "verificationJwt";
 32 
 33    // 指定簽名的時候使用的簽名算法,也就是header那部分,jjwt已經將這部份內容封裝好了。
 34    private static final SignatureAlgorithm SIGNATURE_ALGORITHM = SignatureAlgorithm.HS256;
 35    private static final String JWT_SECRET = "f356cdce935c42328ad2001d7e9552a3";// JWT密匙
 36    private static final SecretKey JWT_KEY;// 使用JWT密匙生成的加密key
 37 // private static final SecretKey JWT_VERIFICATION_KEY;// 使用JWT密匙生成的加密key
 38 
 39 
 40    static {
 41       byte[] encodedKey = Base64.decodeBase64(JWT_SECRET);
 42       JWT_KEY = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
 43 //    這裏我偷個懶,用戶登陸jwt密鑰,與圖形驗證碼jwt密鑰搞成同一個
 44 //    JWT_VERIFICATION_KEY = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
 45    }
 46 
 47    private JwtUtils() {
 48    }
 49 
 50    /**
 51     * 解密jwt,得到全部聲明(包括標準和私有聲明)
 52     * 
 53     * @param jwt
 54     * @return
 55     * @throws Exception
 56     */
 57    public static Claims parseJwt(String jwt) {
 58       Claims claims = Jwts.parser().setSigningKey(JWT_KEY).parseClaimsJws(jwt).getBody();
 59       return claims;
 60    }
 61 
 62    /**
 63     * 建立JWT令牌,簽發時間爲當前時間
 64     * 
 65     * @param claims
 66     *            建立payload的私有聲明(根據特定的業務須要添加,若是要拿這個作驗證,通常是須要和jwt的接收方提早溝通好驗證方式的)
 67     * @param ttlMillis
 68     *            JWT的有效時間(單位毫秒),當前時間+有效時間=過時時間
 69     * @return jwt令牌
 70     */
 71    public static String createJwt(Map<String, Object> claims, long ttlMillis) {
 72       // 生成JWT的時間,即簽發時間
 73       long nowMillis = System.currentTimeMillis();
 74 
 75       // 下面就是在爲payload添加各類標準聲明和私有聲明瞭
 76       // 這裏其實就是new一個JwtBuilder,設置jwt的body
 77       JwtBuilder builder = Jwts.builder()
 78             // 若是有私有聲明,必定要先設置這個本身建立的私有的聲明,這個是給builder的claim賦值,一旦寫在標準的聲明賦值以後,就是覆蓋了那些標準的聲明的
 79             .setClaims(claims)
 80             // 設置jti(JWT ID):是JWT的惟一標識,根據業務須要,這個能夠設置爲一個不重複的值,主要用來做爲一次性token,從而回避重放攻擊。
 81             // 能夠在未登錄前做爲身份標識使用
 82             .setId(UUID.randomUUID().toString().replace("-", ""))
 83             // iss(Issuser)簽發者,寫死
 84             // .setIssuer("zking")
 85             // iat: jwt的簽發時間
 86             .setIssuedAt(new Date(nowMillis))
 87             // 表明這個JWT的主體,即它的全部人,這個是一個json格式的字符串,可放數據{"uid":"zs"}。此處沒放
 88             // .setSubject("{}")
 89             // 設置簽名使用的簽名算法和簽名使用的祕鑰
 90             .signWith(SIGNATURE_ALGORITHM, JWT_KEY)
 91             // 設置JWT的過時時間
 92             .setExpiration(new Date(nowMillis + ttlMillis));
 93 
 94       return builder.compact();
 95    }
 96 
 97    /**
 98     * 複製jwt,並從新設置簽發時間(爲當前時間)和失效時間
 99     * 
100     * @param jwt
101     *            被複制的jwt令牌
102     * @param ttlMillis
103     *            jwt的有效時間(單位毫秒),當前時間+有效時間=過時時間
104     * @return
105     */
106    public static String copyJwt(String jwt, Long ttlMillis) {
107       Claims claims = parseJwt(jwt);
108 
109       // 生成JWT的時間,即簽發時間
110       long nowMillis = System.currentTimeMillis();
111 
112       // 下面就是在爲payload添加各類標準聲明和私有聲明瞭
113       // 這裏其實就是new一個JwtBuilder,設置jwt的body
114       JwtBuilder builder = Jwts.builder()
115             // 若是有私有聲明,必定要先設置這個本身建立的私有的聲明,這個是給builder的claim賦值,一旦寫在標準的聲明賦值以後,就是覆蓋了那些標準的聲明的
116             .setClaims(claims)
117             // 設置jti(JWT ID):是JWT的惟一標識,根據業務須要,這個能夠設置爲一個不重複的值,主要用來做爲一次性token,從而回避重放攻擊。
118             // 能夠在未登錄前做爲身份標識使用
119             //.setId(UUID.randomUUID().toString().replace("-", ""))
120             // iss(Issuser)簽發者,寫死
121             // .setIssuer("zking")
122             // iat: jwt的簽發時間
123             .setIssuedAt(new Date(nowMillis))
124             // 表明這個JWT的主體,即它的全部人,這個是一個json格式的字符串,可放數據{"uid":"zs"}。此處沒放
125             // .setSubject("{}")
126             // 設置簽名使用的簽名算法和簽名使用的祕鑰
127             .signWith(SIGNATURE_ALGORITHM, JWT_KEY)
128             // 設置JWT的過時時間
129             .setExpiration(new Date(nowMillis + ttlMillis));
130       return builder.compact();
131    }
132 
133    public static Claims validateJwtToken(String jwt) {
134       Claims claims = null;
135       try {
136          if (null != jwt) {
137             claims = JwtUtils.parseJwt(jwt);
138          }
139       } catch (Exception e) {
140          e.printStackTrace();
141       }
142       return claims;
143    }
144 }

VerifyCodeUtil

 1 package com.yuan.util;
 2 
 3 import java.util.Random;
 4 
 5 public class VerifyCodeUtil {
 6 
 7 
 8     /**生成N位數字和字母混合的驗證碼
 9      * @param  num 驗證碼位數
10      * @return code 生成的驗證碼字符串*/
11     public static String produceNumAndChar(int num){
12         Random random = new Random();
13         String code = "";
14         String ch = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
15         String n = "123456789";
16         for(int i=0;i<num;i++){
17             int flag = random.nextInt(2);
18             if(flag==0){//數字
19                 code+=n.charAt(random.nextInt(n.length()));
20             }else{//字母
21                 code+=ch.charAt(random.nextInt(ch.length()));
22             }
23         }
24         return code;
25     }
26 }

實體類User

 1 package com.yuan.model;
 2 
 3 public class User {
 4     private String uname;
 5 
 6     private String pwd;
 7 
 8     public User(String uname, String pwd) {
 9         this.uname = uname;
10         this.pwd = pwd;
11     }
12 
13     public User() {
14         super();
15     }
16 
17     public String getUname() {
18         return uname;
19     }
20 
21     public void setUname(String uname) {
22         this.uname = uname;
23     }
24 
25     public String getPwd() {
26         return pwd;
27     }
28 
29     public void setPwd(String pwd) {
30         this.pwd = pwd;
31     }
32 }

UserMapper.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 3 <mapper namespace="com.yuan.mapper.UserMapper">
 4 
 5   <select id="login" parameterType="java.lang.String" >
 6     select 
 7     *
 8     from t_vue_user
 9     where uname = #{uname,jdbcType=VARCHAR}
10   </select>
11 
12 </mapper>

UserMapper

1 package com.yuan.mapper;
2 
3 import com.yuan.model.User;
4 import org.springframework.stereotype.Repository;
5 
6 @Repository
7 public interface UserMapper {
8     User login(User user);
9 }

UserService

package com.yuan.service;

import com.yuan.model.User;

public interface UserService {

        public User login(User user);
}

UserServiceImpl

 1 package com.yuan.service.impl;
 2 
 3 import com.yuan.mapper.UserMapper;
 4 import com.yuan.model.User;
 5 import com.yuan.service.UserService;
 6 import org.springframework.beans.factory.annotation.Autowired;
 7 import org.springframework.stereotype.Service;
 8 
 9 @Service
10 public class UserServiceImpl implements UserService {
11 
12 
13     @Autowired
14     private UserMapper userMapper;
15 
16 
17     @Override
18     public User login(User user) {
19         return userMapper.login(user);
20     }
21 }

UserController

 1 package com.yuan.controller;
 2 
 3 import com.yuan.model.User;
 4 import com.yuan.service.UserService;
 5 import com.yuan.util.ImageUtil;
 6 import com.yuan.util.JSONResult;
 7 import com.yuan.util.JwtUtils;
 8 import com.yuan.util.VerifyCodeUtil;
 9 import io.jsonwebtoken.Claims;
10 import org.springframework.beans.factory.annotation.Autowired;
11 import org.springframework.data.redis.core.RedisTemplate;
12 import org.springframework.stereotype.Controller;
13 import org.springframework.util.StringUtils;
14 import org.springframework.web.bind.annotation.RequestMapping;
15 import org.springframework.web.bind.annotation.ResponseBody;
16 
17 import javax.servlet.http.HttpServletRequest;
18 import javax.servlet.http.HttpServletResponse;
19 import java.io.IOException;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.concurrent.TimeUnit;
23 
24 @Controller
25 @RequestMapping("/vue/user")
26 public class UserController {
27     private static final String VERIFICATION_CODE = "verificationCode_";
28 
29     @Autowired
30     private UserService userService;
31 
32     @Autowired
33     private RedisTemplate redisTemplate;
34 
35     @RequestMapping("/login")
36     @ResponseBody
37     public JSONResult login(User u, HttpServletRequest request, HttpServletResponse response){
38         //獲取用戶輸入的驗證碼
39         String userVerificationCode = request.getParameter("verificationCode");
40         //獲取驗證碼jwt令牌
41         String userJwt = request.getHeader(JwtUtils.JWT_VERIFICATION_KEY);
42         //獲取到保存在redis中的驗證碼
43         Object redisVerificationCode =  redisTemplate.opsForValue().get(VERIFICATION_CODE + userJwt) ;
44 
45 //        這裏存在兩種狀況:一、令牌超時   二、驗證碼超時
46         if(StringUtils.isEmpty(redisVerificationCode)){
47             return JSONResult.errorMsg("你的驗證碼已超時");
48         }
49 
50         if(!redisVerificationCode.toString().equalsIgnoreCase(userVerificationCode)){
51             return JSONResult.errorMsg("驗證碼錯誤");
52         }
53 
54         User user = userService.login(u);
55         //判斷是否登陸成功
56         if(user != null){
57             Map<String,Object> map=new HashMap<String, Object>();
58             map.put("User", user);
59             //這是頒發用戶登陸成功的jwt令牌
60             String jwt= JwtUtils.createJwt(map, JwtUtils.JWT_WEB_TTL);
61             response.setHeader(JwtUtils.JWT_HEADER_KEY, jwt);
62             return JSONResult.ok(user);
63         }else {
64             return JSONResult.errorMsg("密碼或帳戶錯誤");
65         }
66         
67     }
68 
69 
70 
71 
72     /**生成圖片驗證碼*/
73     @RequestMapping("/verificationCode")
74     @ResponseBody
75     public String verificationCode(HttpServletRequest req, HttpServletResponse resp) throws IOException {
76         //生成驗證碼隨機數
77         String word = VerifyCodeUtil.produceNumAndChar(4);
78 //        獲取用戶的jwt令牌
79         String userVerificationJwt = req.getHeader(JwtUtils.JWT_VERIFICATION_KEY);
80         //驗證碼令牌
81         Claims claims = JwtUtils.validateJwtToken(userVerificationJwt);
82         if(claims == null){
83             //若是用戶令牌過時那麼對應存放在redis中的數據也要清空
84             if(!StringUtils.isEmpty(userVerificationJwt)){
85                 redisTemplate.expire(VERIFICATION_CODE + userVerificationJwt, 1, TimeUnit.DAYS);
86             }
87             userVerificationJwt =  JwtUtils.createJwt(new HashMap<String, Object>() ,JwtUtils.JWT_WEB_TTL);
88             //將jwt令牌放入 response head中
89             resp.setHeader(JwtUtils.JWT_VERIFICATION_KEY, userVerificationJwt);
90         }
91         //刷新緩存,更新驗證碼
92         redisTemplate.opsForValue().set(VERIFICATION_CODE + userVerificationJwt , word,60, TimeUnit.SECONDS);
93         //生成圖片
94         String code = "data:image/png;base64," + ImageUtil.createImageWithVerifyCode(word, 116,40);;
95         return code;
96     }
97 }

web.xml

 1 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
 2          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
 4          version="3.1">
 5   <display-name>Archetype Created Web Application</display-name>
 6 
 7   <welcome-file-list>
 8     <welcome-file>login.jsp</welcome-file>
 9   </welcome-file-list>
10 
11   <context-param>
12     <param-name>contextConfigLocation</param-name>
13     <param-value>classpath:applicationContext.xml</param-value>
14   </context-param>
15   <!-- 讀取Spring上下文的監聽器 -->
16   <listener>
17     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
18   </listener>
19   <!-- Spring和web項目集成end -->
20 
21   <!-- 防止Spring內存溢出監聽器 -->
22   <listener>
23     <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
24   </listener>
25 
26     <!-- 中文亂碼處理 -->
27   <filter>
28     <filter-name>encodingFilter</filter-name>
29     <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
30     <!--web.xml 3.0的新特性,是否支持異步-->
31     <async-supported>true</async-supported>
32     <init-param>
33       <param-name>encoding</param-name>
34       <param-value>UTF-8</param-value>
35     </init-param>
36   </filter>
37   <filter-mapping>
38     <filter-name>encodingFilter</filter-name>
39     <url-pattern>/*</url-pattern>
40   </filter-mapping>
41   <!-- 解決cors跨域問題過濾器 -->
42   <filter>
43     <filter-name>corsFilter</filter-name>
44     <filter-class>com.yuan.util.CorsFilter</filter-class>
45   </filter>
46   <filter-mapping>
47     <filter-name>corsFilter</filter-name>
48     <url-pattern>/*</url-pattern>
49   </filter-mapping>
50 
51   <!-- Spring MVC servlet -->
52   <servlet>
53     <servlet-name>SpringMVC</servlet-name>
54     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
55     <!--此參數能夠不配置,默認值爲:/WEB-INF/springmvc-servlet.xml-->
56     <init-param>
57       <param-name>contextConfigLocation</param-name>
58       <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
59     </init-param>
60     <load-on-startup>1</load-on-startup>
61     <!--web.xml 3.0的新特性,是否支持異步-->
62     <async-supported>true</async-supported>
63   </servlet>
64   <servlet-mapping>
65     <servlet-name>SpringMVC</servlet-name>
66     <url-pattern>/</url-pattern>
67   </servlet-mapping>
68 
69 </web-app>

 

最後看一下運行結果

 

謝謝觀看!!!

相關文章
相關標籤/搜索