最近这个项目需要前后端分离,所以涉及到跨域问题,加上使用了拦截器对用户进行登陆验证,各种问题研究了两天才解决,下面是实现过程和讲解。
登陆页面Ajax
var obj = {
"loginName":$("#username").val(),
"password":$("#password").val(),
};
$.ajax({
type: "POST", //提交的方法
dataType: "json",
contentType : 'application/json',
url:IP+"/loginController/userLogin", //提交的地址
data: JSON.stringify(obj);//转换成string数据
async: false,
error: function(request) { //失败的话
alert("失败");
},
success: function(data) { //成功
if(data.meta.code === "0"){
var Token = data.data.token;
localStorage.setItem("token",Token); //本地存储,存储在客户端
window.location.href="index.html";
}
else {
alert(data.meta.message);
}
}
});
localStorage生命周期是永久,这意味着除非用户显示在浏览器提供的UI上清除localStorage信息,否则这些信息将永远存在。存放数据大小为一般为5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。
主页Ajax
var token=localStorage.getItem("token");//获取本地存储的token值
$.ajax({
type: "POST", //提交的方法
dataType: "json",
contentType : 'application/json',
url:IP+"/tResourceController/selectIndexList", //提交的地址
data:{},
beforeSend: function(request) {
request.setRequestHeader("token",localStorage.getItem("token"));},
error: function(request) { //失败的话
alert("请重新登陆");
window.location.href="login.html";
},
success: function(data) { //成功
alert("成功");
}
});
Token工具类
public class TokenUtil {
/**
* 生成token(格式为token:设备-加密的用户名-时间-六位随机数)
* @param username 用户登录名
* @return
*/
public static String generateToken(String username) {
StringBuilder token = new StringBuilder();
//加token:
token.append("token:");
//加加密的用户名
token.append(DigestUtils.md5Hex(username) + "-");
//加时间
token.append(new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + "-");
//加六位随机数111111-999999
token.append(new Random().nextInt((999999 - 111111 + 1)) + 111111);
System.out.println("token=>" + token.toString());
return token.toString();
}
}
登陆接口Controller
@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
@RequestMapping(value = "loginController")
public class LoginController {
private Logger logger = LoggerFactory.getLogger(LoginController.class);
@Autowired
private RedisService redisService;
@Autowired
private UserService userService;
@PostMapping(value = "userLogin")
public ResponseResult userLogin(@RequestBody JSONObject jsonObject,
HttpServletRequest request, HttpServletResponse response) {
String loginName=jsonObject.getString("loginName");
String password=jsonObject.getString("password");
/*
。
。
账号密码相关验证代码略
。
。
*/
//生成token字符串,并以此为标识key将登陆对象的ID存储到redis中
String token=TokenUtil.generateToken(loginName);
redisService.set(token,result.getId());
HashMap hm = new HashMap<>();
hm.put("token", token);
return ResponseResult.success(hm);
}
}
拦截器 Interceptor类
@Component
@CrossOrigin(origins = "*", maxAge = 3600)
public class AccessInterceptor implements HandlerInterceptor {
@Autowired
private RedisService redisService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getMethod().equals("OPTIONS")) {
response.setStatus(HttpServletResponse.SC_OK);
return true;
}
String token = request.getHeader("token");
//判断token是否为空是否过期
if(ConstentUtil.isEmpty(redisService.get(token))){
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
拦截器WebMvcConfigurer配置类
@Configuration
public class MyAdapter implements WebMvcConfigurer {
private Logger logger = LoggerFactory.getLogger(MyAdapter.class);
@Bean
public AccessInterceptor getAccessInterceptor(){
return new AccessInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getAccessInterceptor()).addPathPatterns("/**");
}
@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("*")
.allowCredentials(true);
}
先使用用户名、密码、验证码等进入授权URL获取token,获取到token之后跟后台建立连接继而可以获取数据
一般来说此token是不会往cookie以及localStorage等地方存储的,仅仅放在全局变量中,这时候你换账号登录就没办法获取到了,仅仅限于当前页面且在不刷新的情况下使用;
如果将token存储在可见区域如localStorage,那么是以什么目的呢?记住用户名与密码这种? A登录的时候后台仅仅验证token的话,那确实是可以登录的,网站对安全性没有要求其实无所谓。如果网站要求高,你的token就不能存储成明文了,需要手动加密解密