Java 登录校验

JAVA 实现登录校验

1、简单的登录:

根据输入的用户名和密码,去数据库中查询,可以查到,就登陆成功,查不到就登录失败

缺点(每次登陆后,调转到功能界面,可以通过直接输入功能界面的url 进行访问,无需登录,这样就造成程序失败!
解决: 可以加上一个登陆后的标记! 每次访问功能界面的时候,首先进行登陆的信息校验!)

2、登录校验

用户登录之后,每一次请求,都可以获取到登陆标记!

统一拦截:servlet中的过滤器 Filter Spring中的 拦截器 Interceptor

2.1、会话技术:

**会话:**用户打开浏览器,访问web 服务器的资源,会话建立。直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。

**会话跟踪:**一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便于在同一次会话中的多次请求间共享数据。

会话跟踪方案:

  • 客户端会话跟踪技术: Cookie
/**
cookie : 同一浏览器,不同的请求,cookie一样的
		 请求头 Cookie  就是用来设置cookie的值
		 响应头 Set-Cookie 就是用来获取Cookie的值
优点:Http 协议中,支持的协议
缺点:移动端APP 无法使用cookie
	 不安全,用户可以禁用cookie
	 cookie不可以跨域   跨域(协议+ip/域名:端口号) 三个地址任意一个不一样就是跨域
 */
代码举例:
//设置 cookie
    @GetMapping("/setCookie")
    public R cookie(HttpServletResponse response){
    response.addCookie(new Cookie("login_username","JiaHao"));
    return R.success();
}
//获取Cookie
	@PostMapping("/getCookie")
	public R cookie(HttpServletRequest request){
        Cookie[] cookies = request.getCookies();//获取所有的cookie
        for(Cookie cookie : cookies){
            if(cookie.getName().equals("login_username")){  //遍历cookie,得到name为login_username的cookie的值
                System.out.println("login_username:" + cookie.getValue());
            }
        }
        return R.success();
    }

  • 服务端会话跟踪技术: Session
/**
session: 存储在服务器端的 
		session  就是基于cookie 来实现的
		优点:存储在服务器端,较为安全
		缺点:在多服务器间,无法传播sessionId
			 cookie的缺点 因为sessionId存在cookie中,所以cookie的缺点,session也具有
*/
代码举例:
//往 HttpSession中存储值
    @GetMapping("/setSession")
    public R session (HttpSession session){
    //打印 session的信息
    log.info("HttpSession-s1:",session.hashCode());
    session.setAttribute("loginUser","Xue"); //往session中存值
    return R.success();
}

//从 HttpSession中获取值
	@GetMapping("/getSession")
	public R session(HttpServletRequest request){
        HttpSession session = request.getSession();
        log.info("HttpSession-s2:{}",session.hashCode());
        Object loginUser = session.getAttribute("loginUser"); //从Session中 获取数据
        log.info("loginUser:{}",loginUser);
        return R.success();
    }
    
  • 令牌技术: JWT(token)
/**
JWT令牌技术: 
	优点:支持PC端、移动端
		 解决集群环境下的认证问题
		 减轻服务器端 存储压力
*/

2.2、JWT令牌:

用户身份的标识,本质就是字符串

JWT :全称( JSON Web Token)https://jwt.io/

定义了一种简洁的、自包含的格式,用于在通信双方以 JSON 数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。

组成:

第一部分: Header(头)  记录令牌类型,签名算法等。例如:{"alg":"HS256","type":"JWT"}
第二部分: Payload(有效载荷) , 携带者一些自定义信息,默认信息等,例如:{"id":"1","username":"Xue"}
第三部分: Signature(签名),防止Token 被篡改,确保安全性。将header,payload,并加入指定密钥,通过指定签名算法计算而来。

JWT令牌的生成

①、首先引入相关依赖:

	中电信数公司的
   		   <dependency>
                <groupId>com.tele.toolkit</groupId>
                <artifactId>tele-toolkit-jwt-starter</artifactId>
                <version>${tele-toolkit.version}</version>
            </dependency>
            
     普通的
     		<dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>0.9.1</version>
            </dependency>

②、代码:

生成令牌JWT:

@Test
public void testGenerateJWT(){
    Map<String , Object> claims = new HashMap<>();
    claims.put("id" , 1);
    claims.put("name" , "Xue")
    
    String JWT = Jwts.builder()
        		.signWith(SignatureAlgorithm.HS256 , "Xue")  //签名算法,自定义  第二个参数是自定义密钥/盐值
        		.setClaims(claims)   //里面存的是自定义的内容 (载荷)
        		// System.currentTimeMillis() 获得当前时间的 毫秒值    3600*1000 等于一个小时
        		.setExpiration(new Date(System.currentTimeMillis() + 3600*1000))  //设置有效期 为一小时
        		.compact();  //获取JWT字符串。
}

解析令牌:

@Test
public void parseJWT(String JWT){
Claims  claims = Jwts.parser()
		.setSigningKey("Xue")  //指定签名密钥  也就是盐值
		.parseClaimsJws(JWT)  //解析令牌  传入
		.getBody();  //就是得到自定义的内容的方法
		
		System.out.println(claims);
}

注意事项

  • JWT 校验时使用的签名密钥,必须和生成 JWT 令牌时使用的密钥匙配套的。
  • 如果 JWT 令牌解析校验时报错,则说明 JWT 令牌被篡改 或者 到期失效了 。

在登陆成功的时候,生成令牌,下发令牌
登录失败就返回一个错误信息

//登陆成功,生成令牌,下发令牌
if(e != null){
Map<String , Object> claims = new HashMap<>();
claims.put("id",e.getId());
claims.put("name",e.getName());
    //JwtUtils  是一个生成和解析 JWT的工具类  类似于上面的代码。
   String JWT = JwtUtils.generateJWT(claims);
   return R.success(JWT);
}
//登陆失败,返回错误信息
return R.("用户名或密码错误")

2.3、过滤器Filter:

概念:

Filter 过滤器 ,是Java web三大组件 (Servlet , Filter , Listener)之一。

  • 过滤器可以把对资源的请求拦截下来,从而实现一些特殊功能。
  • 过滤器一般完成一些通用的操作,比如:登录校验,统一编码处理,敏感字符处理等。
快速入门:
  1. 定义过滤器 Filter:定义一个类,实现 Filter 接口,并重写其所有方法。
  2. 配置 Filter :Filter 类上加@WebFilter 注解,配置拦截资源的路径。引导类上加 @ServletComponentScan 开启Servlet 组件支持。
//编写一个类,实现 Filter 接口 ,并且重写 init , doFilter , destory 三个方法。
@WebFilter(urlPatterns = "/*")  //表名当前类是拦截类,urlPatterns拦截的请求 , /*是 拦截所有请求。
		//加上该注解时,还需要在启动类加上@ServletComponentScan 这个注解,因为这是servlet容器的,不是spring boot 容器的 所以要在 spring boot 启动类上加该注解 , 开启servlet组件支持。
public calss DemoFilter implements Filter{
    //init 初始化方法,web服务器启动,创建Filter时调用,只调用一次。
    public void init(FilterConfig filterConfig) throws ServletException{  
        Filter.super.init(filterConfig);
    }
    
    //doFilter 拦截方法 拦截到请求时调用该方法,可调用多次
    public void doFilter(ServletRequest request , SrevletResponse response , FilterChain chain){
        System.out.println("拦截方法执行,拦截到了请求。。。。。");
        //放行  让它去访问对应的资源
        chain.doFilter(request,response);
    }
    
    //销毁方法,服务器关闭时调用,只调用一次
    public void destory(){
        Filter.super.destory();
    }
    
    
}



执行流程:

流程:过滤器拦截到请求,先执行放行之前的逻辑,执行后放行,放行后去访问对应的web资源,访问过后就会回到 Filter 当中,然后执行放行后的操作,

  • 放行后访问对应资源,资源访问完毕之后,还会回到 Filter 之中。
  • 回到 Filter 之中,会执行放行之后的逻辑。
拦截路径:
拦截路径urlPatterns值含义
拦截具体路径/login只有在访问 /login 路径时,才会拦截
目录拦截/emps/*访问 /emps 下的所有资源都会被拦截
拦截所有/*访问所有资源都会被拦截
过滤器链:

**介绍:**一个web 应用中,可以配置多个过滤器,这多个过滤器就形成了一个过滤器链。

**顺序:**注解配置的 Filter ,优先级 是按照过滤器类名(字符串)的自然排序。 A-B-C…Z

比如过滤器A 过滤器B , 程序执行时,首先执行过滤器 A 之前的逻辑,然后放行 ,放行是放行到过滤器B ,然后执行过滤器B的放行之前的逻辑,然后放行,进入到对应的 web 请求资源,返回到过滤器B的放行后的逻辑,然后执行过滤器A的放行后的逻辑。

登录校验功能:

流程:

  1. 获取请求的 url;
  2. 判断请求 url 中是否包含 login ,如果包含,说明是登陆操作,放行;
  3. 获取请求头中的的令牌( token);
  4. 判断令牌是否存在,如果不存在,返回错误结果(未登录);
  5. 解析token ,如果解析失败,返回错误接口板
  6. 放行;

public void doFilter(ServletRequest request , ServletResponse response , FilterChain  chain) throws IOException{
    //1、获取请求的url。 request 获取请求参数   response 响应结果
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resp = (HttpServletResponse) response;
  	String url =  req.getRequestURL().toString();  //获取请求url
    
    //2、判断请求 url 中是否包含 login ,如果包含,说明是登陆操作,放行;
    if(url.contains("login")){
        chain.doFilter(request , response);
        return ;    //因为没有登录所以就不需要进行下面的操作,所以我们直接return之后,就不会进行后续操作。
    }
    
    //3、获取请求头中的的令牌( token);请求参数都在request 中
    String jwt = req.getHeader("token");
    
    //4、判断令牌是否存在,如果不存在,返回错误结果(未登录);
    if(!StringUtils.hasLength(jwt)){  //判断jwt 有没有长度  没有就错,然后证明jwt 为空
        log.info("未登录或登录失效,请重新登录!");
        Result  error = Result.error("NOT_LOGIN");
        //手动转JSON    阿里巴巴 的依赖包  fastjson
        String notLogin = JSONObject.toJSONString(error);  //会将error  转换为JSON 字符串
        resp.getWriter().write(notLogin);  //将次消息响应给客户端
        return ;  //也要return 因为未登录就不许需要继续往下进行  
    }   
    //5、解析token ,如果解析失败,返回错误接口板
    try{
  	  JWTUtils.parseJWT(jwt);   //解析成功就意味着登录,否则就未登录或token到期
    } catch(Exception e){  //解析失败就是异常
        log.info(e);  
        Result  error = Result.error("NOT_LOGIN");
        //手动转JSON    阿里巴巴 的依赖包  fastjson
        String notLogin = JSONObject.toJSONString(error);  //会将error  转换为JSON 字符串
        resp.getWriter().write(notLogin);  //将次消息响应给客户端
        return ;  //也要return 因为未登录就不许需要继续往下进行  
    }
    
    //6、放行;
    //令牌合法,解析成功
    chain.doFilter(request , response);
}




2.4、拦截器 Interceptor:

2.4.1简介:

概念: 是一种动态拦截方法调用的机制,类似于过滤器。Spring 框架中提供的,用来动态拦截控制器方法的执行。

作用: 拦截请求,在指定的方法调用后,根据业务需要 执行预先设定的代码。

2.4.2快速入门:

步骤: 1、定义拦截器,实现 HandlerInterceptor接口,并重写其方法。(preHandel , postHandel , afterCompletion)

​ 2、注册拦截器

//定义拦截器
@Component
public class LoginCheckInterceptor implements HandlerInterceptor{
    @Override  //目标资源方法执行前执行,返回true 放行 ,   返回false 不放行;
    public boolean preHandle(HttpServletRequest req , HttpServletResponse resp , Object handler)throws Exception{
        return true;  //为true 就代表可以运行controller中的方法
    }
    
    @Override  //目标资源方法执行之后执行  在controller 方法执行之后
    public void postHandle(HttpServletRequest req , HttpServletResponse resp , Object handler,ModelAndView modelAndView){
        
    }
    
    @Override  // 视图渲染完毕之后执行,   最后最后执行
    public void afterCompletion(HttpServletRequest req , HttpServletResponse resp , Object handler , Exception ex){
        
        
	}   
}

//注册配置拦截器
@Configuration   //表明是配置类
public class WebConfig implements WebMvcConfigurer{
    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
        
    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");  //   /**表明拦截所有
    }
}


2.4.3详解:

拦截路径:

addPathPatterns("/**");   //  需要拦截哪些资源
excludePathPatterns("/login");  //不需要拦截哪些资源
拦截路径含义举例
/*一级路径能匹配/depts , /emps , /login , 不能匹配/depts/1
/**任意级路径能匹配 /depts , /depts/1 , /depts/1/2
/depts/*/depts 下的一级路径能匹配 /depts/1 , 不能匹配 /depts/1/2 , /depts
/depts/**/depts 下的任意级路径能匹配 /depts , /depts/1 , /depts/1/2, 不能匹配 /emps/1

执行流程:

如果过滤器和拦截器同时存在的话,那么请求会先经过过滤器,然后进入到拦截器,具体为:发送请求,过滤器拦截到请求之后,会过滤请求,然后 请求进入到spring 容器 ,DispatcherServlet 发送请求 拦截器拦截到请求,拦截过后,请求到达 controller 然后返回给拦截器,返回到 DispatcherServlet ,返回到 过滤器,最终返回给浏览器。

过滤器 Filter 和 拦截器 Interceptor

**接口规范不同:**过滤器需要实现 Filter 接口 ,拦截器需要实现 HandlerInterceptor 接口

**拦截范围不同:**过滤器(范围更大)会拦截所有的资源, 而拦截器 Interceptor 只会拦截 Spring 环境中的资源。

2.4.4登录校验-Interceptor:

步骤(同过滤器一致)

  1. 获取请求的 url;
  2. 判断请求 url 中是否包含 login ,如果包含,说明是登陆操作,放行;
  3. 获取请求头中的的令牌( token);
  4. 判断令牌是否存在,如果不存在,返回错误结果(未登录);
  5. 解析token ,如果解析失败,返回错误接口板
  6. 放行;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值