登录校验(会话跟踪、JWT令牌、Filter、Interceptor、全局异常处理器)

目录

会话技术 

会话跟踪方案

客户端会话跟踪技术:Cookie

服务端会话跟踪技术:Session

​编辑

令牌技术(JWT令牌)

 生成JWT

解析JWT

登录的实现

Filter 

入门

详解 

执行流程

拦截路径 

过滤器链 

登录校验Filter的实现 

思路

拦截器Interceptor 

入门 

详解

拦截路径

执行流程

与Filter的区别 

登录校验Interceptor的实现 

异常处理


 

会话技术 

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

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

会话跟踪方案

客户端会话跟踪技术:Cookie

@Slf4j
@RestController
public class CookieController {
    //设置cookie
    @GetMapping("c1")
    public Result cookie(HttpServletResponse response){
   response.addCookie(new Cookie("login_username","itheima"));
   return Result.success();
    }
    //获取cookie
    @GetMapping("c2")
    public Result cookie2(HttpServletRequest request){
        Cookie[] cookies=request.getCookies();//获取所有的cookie 
        for(Cookie cookie:cookies){
            if (cookie.getName().equals("login_username")){
                System.out.println("login_username:"+cookie.getValue());
            }
        }
        return Result.success();
    }
}

服务端会话跟踪技术:Session

  //往httpSession中存储
    @GetMapping("s1")
    public Result session1(HttpSession session){
        log.info("HttpSession-s1:{}",session.hashCode());
        session.setAttribute("loginUser","tom");//往session中存储
        return Result.success();
    }
    //往httpSession中存储
    @GetMapping("s2")
    public Result session2(HttpServletRequest request){
        HttpSession session=request.getSession();
        log.info("httpSession-s2:{}",session.hashCode());
        Object loginUser=session.getAttribute("loginUser");//从session中获取数据
        log.info("loginUser:{}",loginUser);
   return Result.success(loginUser);
    }

令牌技术(JWT令牌)

JWT定义 

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

应用场景:登录认证

登陆成功后生成令牌,后续每个请求,都要携带JWT令牌,系统在每次请求处理之前,先校验令牌,通过后,再处理

 生成JWT

//生成jwt令牌
@Test
public void testGenJwt(){
	Map<String,Object> claims=new HashMap<>();
	claims.put("id",1);
	claims.put("name","tom");
	String jwt=Jwts.builder()
			.signWith(SignatureAlgorithm.HS256,"itheima")//签名算法
	        .setClaims(claims)//自定义内容(载荷)
	        .setExpiration(new Date(System.currentTimeMillis()+3600*1000))//设置有效期为1小时
	        .compact();
	System.out.println(jwt);
}

解析JWT

	//解析JWT
	@Test
	public void testParseJwt(){
		Claims claims=Jwts.parser()
				.setSigningKey("itheima")//指定签名密钥
				.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTcyMTc5MzA3Nn0.sr9O2q23mb85qVNRABlL9hj0KCMfkYtoRYEn7t3T5qM")//解析令牌
				.getBody();
		System.out.println(claims);
	}

 生成令牌以后,篡改任意一个位置都会报错!

JWT校验时使用的签名密钥,必须和生成的JWT令牌时使用的密钥时配套的

如果JWT令牌解析校验时报错,则说明JWT令牌被篡改或者失效了,令牌非法 

登录的实现

@Slf4j
@RestController
public class LoginController {
    @Autowired
    private EmpService empService;
    @PostMapping("/login")
    public Result login(@RequestBody Emp emp){
log.info("员工登录{}",emp);
Emp e=empService.login(emp);
//登陆成功,生成令牌,下发令牌
        if (e!=null){
            Map<String, Object> claims=new HashMap<>();
            claims.put("id",e.getId());
            claims.put("name",e.getName());
            claims.put("username",e.getUsername());
            String jwt= JwtUtils.generateJwt(claims);//jwt包含了当前登录的员工信息
            return Result.success(jwt);
        }
        //登陆失败,返回信息
return Result.error("用户名或者密码错误");
    }
}
public class JwtUtils {
    private static String signKey="itheima";
    private static Long expire=43200000L;
    /*
    生成JWT令牌
    JWT第二部分负载payload中存储的内容
     */
    public static String generateJwt(Map<String,Object> claims){
        String jwt= Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.HS256,signKey)//签名算法

                .setExpiration(new Date(System.currentTimeMillis()+expire))//设置有效期为1小时
                .compact();
        return jwt;
    }
    /*
    解析
     */
    public static Claims paraseJwt(String jwt){
        Claims claims=Jwts.parser()
                .setSigningKey(signKey)//指定签名密钥
                .parseClaimsJws(jwt)//解析令牌
                .getBody();
        return claims;
    }
}

Filter 

入门

@WebFilter(urlPatterns = "/*")//拦截所有请求
public class DemoFilter implements Filter {
    @Override//初始化方法,只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init 初始化方法执行了");
    }

    @Override//拦截到请求后调用,调用多次
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("拦截到了请求");
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {//销毁方法,只调用一次
        System.out.println("destroy销毁方法执行了");
    }
}

这里如果没有放行操作的话,访问了这个网址但是不会显示数据,只有放行以后,才可以有数据显示。

@ServletComponentScan   //加上这个才能对servlet组件的加载
@SpringBootApplication
public class SpringPractice1Application {
    public SpringPractice1Application() {
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringPractice1Application.class, args);
    }
}

详解 

执行流程

请求-->放行前逻辑--> 放行--> 资源--> 放行后逻辑

拦截路径 

过滤器链 

比如AbcFilter和DemoFilter 就是AbcFilter先执行

登录校验Filter的实现 

思路

@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req=(HttpServletRequest) servletRequest;
        HttpServletResponse resp=(HttpServletResponse) servletResponse;
        //获取请求url
        String url=req.getRequestURL().toString();
        log.info("获取url:{}",url);
        //判断url中是否包含login,如果包含,登录请求,放行
        if(url.contains("login")){
            log.info("登录操作,放行");
            filterChain.doFilter(servletRequest,servletResponse);
            return;
        }
        //获取请求头中的令牌(token)
         String jwt=req.getHeader("token");

        //判断令牌是否存在,如果不存在,返回错误结果(未登录)
         if(!StringUtils.hasLength(jwt)){
            log.info("请求头为空,返回未登陆信息");
            Result error=Result.error("NOT_LOGIN");
            //手动转换对象为json-----阿里巴巴
             String notLogin=JSONObject.toJSONString(error);
             resp.getWriter().write(notLogin);
             return;
         }
        //解析token,如果解析失败,返回错误信息(未登录)
       try {
           JwtUtils.paraseJwt(jwt);
       }catch (Exception e){//jwt解析失败
           log.info("解析令牌失败,返回未登录错误信息");
           Result error=Result.error("NOT_LOGIN");
           //手动转换对象为json
           String notLogin=JSONObject.toJSONString(error);
           resp.getWriter().write(notLogin);
           return;

       }
        //放行
        log.info("令牌合法,放行");
        filterChain.doFilter(servletRequest,servletResponse);
    }

把对象转化为json,需要引入阿里巴巴的依赖 

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.76</version>
		</dependency>

登录操作时的后台

 

拦截器Interceptor 

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

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

 

入门 

定义拦截器 

//定义拦截器
@Component//交给ioc容器
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override//目标资源方法运行前运行,返回true:放行,返回false:不放行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("prehandle...");
        return true;
    }

    @Override//目标资源运行后运行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("psothandle...");
    }

    @Override//视图渲染完毕后运行,最后运行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion"
        );
    }
}

 配置拦截器

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

详解

拦截路径

执行流程

与Filter的区别 

登录校验Interceptor的实现 

@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {
   @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");//拦截所有
    }
}
//定义拦截器
@Component//交给ioc容器
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
    @Override//目标资源方法运行前运行,返回true:放行,返回false:不放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {

            //获取请求url
            String url=req.getRequestURL().toString();
            log.info("获取url:{}",url);
            //判断url中是否包含login,如果包含,登录请求,放行
            if(url.contains("login")){
                log.info("登录操作,放行");

                return true;
            }
            //获取请求头中的令牌(token)
            String jwt=req.getHeader("token");

            //判断令牌是否存在,如果不存在,返回错误结果(未登录)
            if(!StringUtils.hasLength(jwt)){
                log.info("请求头为空,返回未登陆信息");
                Result error=Result.error("NOT_LOGIN");
                //手动转换对象为json-----阿里巴巴
                String notLogin= JSONObject.toJSONString(error);
                resp.getWriter().write(notLogin);
                return false;
            }
            //解析token,如果解析失败,返回错误信息(未登录)
            try {
                JwtUtils.paraseJwt(jwt);
            }catch (Exception e){//jwt解析失败
                log.info("解析令牌失败,返回未登录错误信息");
                Result error=Result.error("NOT_LOGIN");
                //手动转换对象为json
                String notLogin=JSONObject.toJSONString(error);
                resp.getWriter().write(notLogin);
                return false;

            }
            //放行
            log.info("令牌合法,放行");
            return  true;

    }


    @Override//目标资源运行后运行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("psothandle...");
    }

    @Override//视图渲染完毕后运行,最后运行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion"
        );
    }
}

异常处理

/*
全局异常处理器
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)//捕获所有异常
    public Result ex(Exception ex){
        ex.printStackTrace();
        return Result.error("对不起,操作失败了,请联系管理员");
    }
}

 @RestControllerAdvice=@ControllerAdvice+@ResponseBody

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值