转自博客 https://blog.csdn.net/weixin_39102174/article/details/90411116
以上博主讲的更清除些,此博客是为了自己加深记忆。
对于前后端分离的项目来说session来判断是否登陆实现比较困难,token是比较好的方式。
大概流程:
1.用户登陆,若成功则后台生成一个token,并把此token返回给客户端浏览器
2.客户端接收到token后,每次请求都要把此token放到header中发给后段
3.后段使用拦截器判断token的正确性和实效性。
以下是具体代码:
Token工具类:
- package com.sign;
- import com.auth0.jwt.JWT;
-
import com.auth0.jwt.JWTVerifier;
-
import com.auth0.jwt.algorithms.Algorithm;
-
import com.auth0.jwt.exceptions.JWTDecodeException;
-
import com.auth0.jwt.interfaces.DecodedJWT;
-
import java.util.Date;
-
import java.util.HashMap;
-
import java.util.Map;
-
public class TokenSign {
-
/**
-
* 过期时间60分钟
-
*/
-
private static final long EXPIRE_TIME=60 * 60 *1000;
-
/**
-
* 私钥,使用它生成token,最好进行下加密
-
*/
-
private static final String TOKEN_SECRET="Token";
-
/**
-
* 产生token
-
* @param useName
-
* @param userId
-
* @return
-
*/
-
public static String sign(String useName,String userId){
-
try{
-
//设置15分钟失效
-
Date date=new Date(System.currentTimeMillis()+EXPIRE_TIME);
-
//私钥及加密算法
-
Algorithm algorithm=Algorithm.HMAC256(TOKEN_SECRET);
-
//设置头部信息
-
Map<String,Object> header=new HashMap<>();
-
header.put("typ","JWT");
-
header.put("alg","HS256");
-
//附带username和userid信息,存储到token中,生成签名
-
return JWT.create()
-
.withHeader(header)
-
//存储自己想要留存给客户端浏览器的内容
-
.withClaim("userName",useName)
-
.withClaim("userId",userId)
-
.withExpiresAt(date)
-
.sign(algorithm);
-
}catch (Exception e){
-
e.printStackTrace();
-
}
-
return null;
-
}
-
/**
-
* token校验是否正确
-
* @param token
-
* @return
-
*/
-
public static boolean verify(String token){
-
try {
-
Algorithm algorithm=Algorithm.HMAC256(TOKEN_SECRET);
-
JWTVerifier verifier =JWT.require(algorithm).build();
-
//此方法若token验证失败会抛错的,所以直接return true没问题
-
DecodedJWT decodedJWT =verifier.verify(token);
-
return true;
-
}catch (Exception e){
-
e.printStackTrace();
-
}
-
return false;
-
}
-
/**
-
* 获取token中信息 userName
-
* @param token
-
* @return
-
*/
-
public static String getUsername(String token) {
-
try {
-
DecodedJWT jwt = JWT.decode(token);
-
return jwt.getClaim("userName").asString();
-
} catch (JWTDecodeException e) {
-
e.getStackTrace();
-
}
-
return null;
-
}
-
/**
-
* 获取token中信息 userId
-
* @param token
-
* @return
-
*/
-
public static String getUserId(String token) {
-
try {
-
DecodedJWT jwt = JWT.decode(token);
-
return jwt.getClaim("userId").asString();
-
} catch (JWTDecodeException e) {
-
e.getStackTrace();
-
}
-
return null;
-
}
-
}
拦截器:
-
package com.interceptor;
-
import com.alibaba.fastjson.JSONObject;
-
import com.constant.TokenConstant;
-
import com.sign.TokenSign;
-
import org.springframework.stereotype.Component;
-
import org.springframework.web.servlet.HandlerInterceptor;
-
import org.springframework.web.servlet.ModelAndView;
-
import javax.servlet.http.HttpServletRequest;
-
import javax.servlet.http.HttpServletResponse;
-
import java.util.HashMap;
-
import java.util.Map;
-
@Component
-
public class LoginInterceptor implements HandlerInterceptor {
-
// 在请求处理之前调用,只有返回true才会执行要执行的请求
-
@Override
-
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
-
httpServletResponse.setCharacterEncoding("UTF-8");
-
String token=httpServletRequest.getHeader("accessToken");
-
if (null==token){
-
Map<String,Object> map=new HashMap<>();
-
map.put("data","token is null");
-
map.put("code","401");
-
httpServletResponse.getWriter().write(JSONObject.toJSONString(map));
-
return false;
-
}else {
-
boolean result= TokenSign.verify(token);
-
if (result){
-
//更新存储的token信息
-
TokenConstant.updateTokenMap(token);
-
return true;
-
}
-
Map<String,Object> map=new HashMap<>();
-
map.put("data","token is null");
-
map.put("code","401");
-
httpServletResponse.getWriter().write(JSONObject.toJSONString(map));
-
return false;
-
}
-
}
-
// 试图渲染之后执行
-
@Override
-
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
-
}
-
// 在请求处理之后,视图渲染之前执行
-
@Override
-
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
-
}
-
}
-
package com.constant;
-
import java.util.HashMap;
-
import java.util.Map;
-
public class TokenConstant {
-
private static Map<String,String> map=new HashMap();
-
public static String getToken(){
-
return map.get("token");
-
}
-
public static void updateTokenMap(String token){
-
map.put("token",token);
-
}
-
}
注册拦截器:
-
package com.adapter;
-
import com.interceptor.LoginInterceptor;
-
import org.springframework.beans.factory.annotation.Autowired;
-
import org.springframework.context.annotation.Configuration;
-
import org.springframework.web.servlet.config.annotation.CorsRegistry;
-
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
-
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
@Configuration
-
public class LoginAdapter implements WebMvcConfigurer {
-
//解决跨域问题
-
@Override
-
public void addCorsMappings(CorsRegistry registry) {
-
registry.addMapping("/**")
-
.allowedHeaders("Content-Type","X-Requested-With","accept,Origin","Access-Control-Request-Method","Access-Control-Request-Headers","token")
-
.allowedMethods("*")
-
.allowedOrigins("*")
-
//是否允许使用cookie
-
.allowCredentials(true);
-
}
-
@Autowired
-
private LoginInterceptor loginInterceptor;
-
// 这个方法是用来配置静态资源的,比如html,js,css,等等
-
@Override
-
public void addResourceHandlers(ResourceHandlerRegistry registry) {
-
}
-
// 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
-
@Override
-
public void addInterceptors(InterceptorRegistry registry) {
-
System.out.println("进入拦截器");
-
//addPathPatterns是表明拦截哪些请求
-
//excludePathPatterns是对哪些请求不做拦截
-
registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/user/login");
-
}
-
}
以上是后台的配置,除了登陆所有请求都会进行token验证。
前端代码概要:
前端用的VUE
-
<template>
-
<div class="login">
-
<!--打包时用这个-->
-
<div class="welcome"><img src="/dist/static/image/welcome.png"></div>
-
<!--本地用这个-->
-
<!--<div class="welcome"><img src="/static/image/welcome.png"></div>-->
-
<div class="login-form">
-
<div class="login-inp"><label>账号</label><input type="text" placeholder="请输入账号" v-model="user.account"></div>
-
<div class="login-inp"><label>密码</label><input type="password" placeholder="请输入密码" v-model="user.password"></div>
-
<div class="login-inp" v-show="!loadingShow" v-on:click="ok()">
-
<input type="button" value="立即登录" />
-
</div>
-
</div>
-
<!--加载效果-->
-
<wv-loadmore v-show="this.loadingShow"></wv-loadmore>
-
</div>
-
</template>
-
<script>
-
import Vue from ‘vue‘;
-
import Axios from ‘axios‘
-
import { Toast } from ‘we-vue‘
-
export default {
-
name: ‘Login‘,
-
data: function () {
-
return {
-
user: {account: ‘‘, password: ‘‘},
-
show: false,
-
url:this.GLOBAL.loginUrl,
-
isDisable:false,
-
loadingShow:false
-
}
-
},
-
methods: {
-
ok: function () {
-
if (!this.user.account || !this.user.password) {
-
// Toast.loading(‘加载中‘);
-
Toast.text(‘请完善登陆信息‘);
-
console.log(‘param not allow null‘)
-
return
-
};
-
this.isDisable=true;
-
this.loadingShow=true;
-
setTimeout(() => {
-
Axios.post(this.url,
-
this.user,
-
{ //方式2通过transformRequest方法发送数据,本质还是将数据拼接成字符串
-
transformRequest:[
-
function(data){
-
let params=‘‘;
-
for(let index in data){
-
params+=index+‘=‘+data[index]+‘&‘;
-
}
-
return params;
-
}
-
]
-
})
-
.then(response => {
-
if (response.data) {
-
//存储token
-
localStorage.setItem(‘accessToken‘, response.data);
-
this.$router.push({ path: ‘home‘ })
-
}else {
-
Toast.fail(‘登陆失败‘);
-
console.log(‘登陆失败:‘, response.data.message)
-
}
-
this.loadingShow=false;
-
this.isDisable=false;
-
})
-
.catch(error => {
-
Toast.fail(‘请求失败‘);
-
console.log(‘请求失败:‘, error)
-
this.loadingShow=false;
-
this.isDisable=false;
-
})
-
}, 1000)
-
},
-
cancel: function () {
-
this.show = false
-
this.$emit(‘cancel‘, this.flowParam)
-
}
-
}
-
}
-
</script>
登陆界面最主要的是:localStorage.setItem(‘accessToken‘, response.data);把token信息存储
每次请求都放到header中:
此处简写:
-
Axios.post(this.addUrl,param,
-
{headers: {‘Content-Type‘:‘application/json;charset=UTF-8‘,‘accessToken‘:localStorage.getItem(‘accessToken‘)}},
-
{method: ‘put‘}
-
).then(response => {
localStorage.getItem(‘accessToken‘);获取存储在localStorage中的token信息
原文地址:https://www.cnblogs.com/EarlyBridVic/p/12532658.html