一.后端
?
后端目錄:
?
?
?
1.pom依賴(lài)需引入jwt
<dependency>
? <groupId>io.jsonwebtoken</groupId>
? <artifactId>jjwt</artifactId>
? <version>0.9.0</version>
</dependency>
2.token工具類(lèi),用來(lái)生成token以及校驗(yàn)token
public class TokenUtil {
? public static void main(String[] args) {
? ? ? User u = new User("admin","123");
? ? ? System.out.println(sign(u));
? }
? private static final long EXPIRE_TIME = 10*60*60*1000;
? private static final String PRIVATE_KEY = "abcde"; //密鑰
?
? /**
? ? * 簽名生成
? ? * @param user
? ? * @return
? ? */
? public static String sign(User user){
? ? ? String token = null;
? ? ? Map<String,Object> header = new HashMap<>();
? ? ? header.put("typ","JWT");
? ? ? header.put("alg","HS256");
? ? ? Map<String,Object> claims = new HashMap<>();
? ? ? //自定義有效載荷部分
? ? ? claims.put("account",user.getUserId());
? ? ? token = Jwts.builder()
? ? ? ? ? ? ? //發(fā)證人
? ? ? ? ? ? ? .setIssuer("auth")
? ? ? ? ? ? ? //Jwt頭
? ? ? ? ? ? ? .setHeader(header)
? ? ? ? ? ? ? //有效載荷
? ? ? ? ? ? ? .setClaims(claims)
? ? ? ? ? ? ? //設(shè)定簽發(fā)時(shí)間
? ? ? ? ? ? ? .setIssuedAt(new Date())
? ? ? ? ? ? ? //設(shè)定過(guò)期時(shí)間
? ? ? ? ? ? ? .setExpiration(new Date(System.currentTimeMillis() + EXPIRE_TIME))
? ? ? ? ? ? ? //使用HS256算法簽名,PRIVATE_KEY為簽名密鑰
? ? ? ? ? ? ? .signWith(SignatureAlgorithm.HS256,PRIVATE_KEY)
? ? ? ? ? ? ? .compact();
? ? ? return token;
? }
?
? /**
? ? * 驗(yàn)證 token信息 是否正確
? ? * @param token 被解析 JWT
? ? * @return 是否正確
? ? */
? public static boolean verify(String token){
? ? ? //獲取簽名密鑰
? ? ? //String key = userEntity.getUserPassword();
? ? ? //獲取DefaultJwtParser
? ? ? try{
? ? ? ? ? Jwts.parser()
? ? ? ? ? ? ? ? ? //設(shè)置 密鑰
? ? ? ? ? ? ? ? ? .setSigningKey(PRIVATE_KEY)
? ? ? ? ? ? ? ? ? //設(shè)置需要解析的 token
? ? ? ? ? ? ? ? ? .parseClaimsJws(token).getBody();
? ? ? ? ? return true;
? ? ? }catch (Exception e){
? ? ? ? ? return false;
? ? ? }
? }
}
3.TokenInterceptor 攔截器
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {
?
? // 重寫(xiě) 前置攔截方法
? @Override
? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
? ? ? ? ? throws Exception {
? ? ? if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
? ? ? ? ? System.out.println("OPTIONS請(qǐng)求,放行");
? ? ? ? ? return true;
? ? ? }
? ? ? // 1、從請(qǐng)求頭中獲取token
? ? ? String token = request.getHeader("token");
? ? ? System.out.println(token);
? ? ? // 2、判斷 token 是否存在
? ? ? if (token == null || "".equals(token)) {
? ? ? ? ? System.out.println("未登錄");
? ? ? ? ? return false;
? ? ? }
?
? ? ? // 3、解析token
? ? ? if(!TokenUtil.verify(token)){
? ? ? ? ? return false;
? ? ? }
?
? ? ? return true;
? }
}
4.WebMvcConfig 注冊(cè)攔截器
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
?
? // 注入 token 攔截器
? @Autowired
? private TokenInterceptor interceptor;
?
? /**
? ? * 重寫(xiě)添加攔截器
? ? */
? @Override
? public void addInterceptors(InterceptorRegistry registry) {
? ? ? // 添加自定義攔截器,并攔截對(duì)應(yīng) url"
? ? ? registry.addInterceptor(interceptor).addPathPatterns("/**").excludePathPatterns("/login");
? }
}
5.User實(shí)體類(lèi)
public class User {
? private String userId;
? private String password;
?
? public User(String id,String word){
? ? ? this.userId = id;
? ? ? this.password = word;
? }
? public String getUserId() {
? ? ? return userId;
? }
?
? public void setUserId(String userId) {
? ? ? this.userId = userId;
? }
?
? public String getPassword() {
? ? ? return password;
? }
?
? public void setPassword(String password) {
? ? ? this.password = password;
? }
}
6.controller接口
@CrossOrigin
@RestController
public class UserController{
? @RequestMapping(value = "/login",method = RequestMethod.POST)
? @ResponseBody
? public String login(@RequestBody Map<String,String> para) throws JsonProcessingException {
? ? ? String username=para.get("username");
? ? ? String password=para.get("password");
? ? ? String token= TokenUtil.sign(new User(username,password));
? ? ? HashMap<String,Object> hs=new HashMap<>();
? ? ? hs.put("token",token);
? ? ? ObjectMapper objectMapper=new ObjectMapper();
? ? ? return objectMapper.writeValueAsString(hs);
? }
?
? @RequestMapping(value = "/demo",method = RequestMethod.POST)
? public String hello(){
? ? ? System.out.println("sdhfkhsdf");
? ? ? return "Nihao ";
? } ?
}
二.前端
前端目錄:one.vue頁(yè)面是多余的 不用管
?
?
?
1.登錄頁(yè)面
<template>
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="auto" class="demo-ruleForm" >
<el-form-item label-width="300px" >
</el-form-item>
<el-form-item label="賬號(hào):" label-width="50px" prop="pass">
<el-input clearable name="name" type="username" v-model.trim="ruleForm.pass" autocomplete="off" placeholder="請(qǐng)輸入賬號(hào)" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label="密碼:" label-width="50px" prop="checkPass">
<el-input clearable name="word" type="password" v-model.trim="ruleForm.checkPass" autocomplete="off" placeholder="請(qǐng)輸入密碼" style="width: 250px"></el-input>
</el-form-item>
<el-form-item label-width="95px">
<el-button type="primary" @click="handleSubmit">登錄</el-button>
</el-form-item>
</el-form>
</div>
</template>
?
export default {
data () {
var validatePass = (rule, value, callback) => {
if (value === '') {
callback(new Error('請(qǐng)輸入賬號(hào)'))
}
}
var validatePass2 = (rule, value, callback) => {
if (value === '') {
callback(new Error('請(qǐng)輸入密碼'))
}
}
return {
ruleForm: {
pass: '',
checkPass: ''
},
userToken: '',
userid: '',
userword: '',
rules: {
pass: [
{ validator: validatePass, trigger: 'blur' }
],
checkPass: [
{ validator: validatePass2, trigger: 'blur' }
]
}
}
},
methods: {
handleSubmit () {
let params = {
'username': this.ruleForm.pass,
'password': this.ruleForm.checkPass
}
?
this.$axios.post('http://localhost:8080/login', params).then(res => {
// 請(qǐng)求成功
?
console.log(res.data)
this.userToken = res.data.token
// 將用戶(hù)token保存
alert(this.userToken)
localStorage.setItem('token', this.userToken)
?
this.$router.push('/main')
}).catch(() => {
// 請(qǐng)求失敗,
this.$Message.error('登錄失敗!請(qǐng)檢查登錄信息是否正確!')
})
}
}
}
</script>
.login{
position: absolute;/絕對(duì)定位/
width: 300px;
height: 200px;
text-align: center;/(讓div中的內(nèi)容居中)/
top: 50%;
left: 50%;
margin-top: -200px;
margin-left: -150px;
}
</style>
2.登錄成功后的main頁(yè)面(為了測(cè)試,就只寫(xiě)了一個(gè)按鈕,登錄成功后,跳轉(zhuǎn)到這個(gè)頁(yè)面,再點(diǎn)擊按鈕返回一條后端信息)
<template>
<el-button type="primary" @click="mount">登錄</el-button>
</div>
</template>
export default {
methods: {
mount () {
alert(localStorage.getItem('token'))
this.$axios.post('http://localhost:8080/demo').then(res => {
// 請(qǐng)求成功
alert(res.data)
}).catch(() => {
// 請(qǐng)求失敗,
alert(222)
})
}
}
}
</script>
3.main.js中加入全局配置請(qǐng)求頭代碼
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'
import axios from 'axios'
import 'element-ui/lib/theme-chalk/index.css'
import Vuex from 'vuex'
?
Vue.use(Vuex)
Vue.use(ElementUI)
Vue.prototype.$axios = axios
Vue.config.productionTip = false
?
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
axios.interceptors.request.use(function (config) {
// 為請(qǐng)求頭添加Authorization字段為服務(wù)端返回的token
config.headers.token = localStorage.getItem('token')
// return config是固定用法 必須有返回值
return config
})
三.測(cè)試
前端頁(yè)面路由:(one這個(gè)是多余的不用管,到時(shí)候直接輸入8081/login頁(yè)面就行)
?
?
?
打開(kāi)url:http://localhost:8081/#/login
?
?
隨便輸入賬號(hào)和密碼就行,為了測(cè)試,后端沒(méi)有去從數(shù)據(jù)庫(kù)拿數(shù)據(jù),登錄后跳轉(zhuǎn)到main頁(yè)面
?
?
點(diǎn)擊登錄按鈕:
?
?
?
?
?
成功!
?
本文摘自 :https://www.cnblogs.com/