最近这个项目需要前后端分离,所以涉及到跨域问题,加上使用了拦截器对用户进行登陆验证,各种问题研究了两天才解决,下面是实现过程和讲解。

前端代码:

登陆页面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<String, Object> 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之后跟后台建立连接继而可以获取数据

  1. 一般来说此token是不会往cookie以及localStorage等地方存储的,仅仅放在全局变量中,这时候你换账号登录就没办法获取到了,仅仅限于当前页面且在不刷新的情况下使用;
  2. 如果将token存储在可见区域如localStorage,那么是以什么目的呢?记住用户名与密码这种? A登录的时候后台仅仅验证token的话,那确实是可以登录的,网站对安全性没有要求其实无所谓。如果网站要求高,你的token就不能存储成明文了,需要手动加密解密