当前位置: 首页 > news >正文

【JavaWeb学习Day20】

Tlias智能学习系统

员工登录

三层架构:

Controller:1.接收请求参数(用户名,密码)2.调用Service方法3.响应结果

具体实现:

/**
 * 登录
 */
​
@PostMapping("/login")
public Result login(@RequestBody Emp emp){
    log.info("登录:{}",emp);
    LoginInfo info = empService.login(emp);
    if(info != null){
        return Result.success(info);
    }
    return Result.error("用户名或密码错误");
}

Service:1.根据用户名和密码查询员工信息2.判定,组装数据并放回

具体实现:

/**
 * 登录
 */
@Override
public LoginInfo login(Emp emp) {
    //1.调用Mapper接口,根据用户名和密码查询员工信息
    Emp e = empMapper.selectByUsernamePassword(emp);
    //2.判断:判断是否存在这个员工,如果存在,组装登录信息
    if(e!=null){
        log.info("登录成功,员工信息:{}",e);
        return new LoginInfo(e.getId(),e.getUsername(),e.getName(),"");
    }
    //3.不存在,放回null
    return null;
}

Mapper:SQL:select * from emp where username ='shinaian' and password ='123456';

具体实现:

/**
 * 登录
 */
@Select("select id,username,name from emp where username = #{username} and password = #{password}")
Emp selectByUsernamePassword(Emp emp);

联调测试:

问题:在未登录的情况下,我们也可以直接访问部门管理、员工管理等功能

需求:只有在员工登录成功,才可以访问后台系统中的数据。

登录校验:

登录标记:用户登录成功之后,在后续的每一次请求中,都可以获取到该标记。【会话技术】

统一拦截:过滤器Filter、拦截器:Interceptor

会话技术:

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

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

会话跟踪方案:

1.客户端会话跟踪技术:Cookie

2.服务端会话跟踪技术:Session

/**
​
 * HttpSession演示
   */
   @Slf4j
   @RestController
   public class SessionController {
​
   //设置Cookie
   @GetMapping("/c1")
   public Result cookie1(HttpServletResponse response){
       response.addCookie(new Cookie("login_username","itheima")); //设置Cookie/响应Cookie
       return Result.success();
   }
​
   //获取Cookie
   @GetMapping("/c2")
   public Result cookie2(HttpServletRequest request){
       Cookie[] cookies = request.getCookies();
       for (Cookie cookie : cookies) {
           if(cookie.getName().equals("login_username")){
               System.out.println("login_username: "+cookie.getValue()); //输出name为login_username的cookie
           }
       }
       return Result.success();
   }
​
​
@GetMapping("/s1")
public Result session1(HttpSession session){
    log.info("HttpSession-s1: {}", session.hashCode());
​
    session.setAttribute("loginUser", "tom"); //往session中存储数据
    return Result.success();
}
​
@GetMapping("/s2")
public Result session2(HttpSession session){
    log.info("HttpSession-s2: {}", session.hashCode());
​
    Object loginUser = session.getAttribute("loginUser"); //从session中获取数据
    log.info("loginUser: {}", loginUser);
    return Result.success(loginUser);
}
}   

3.令牌技术

JWT令牌—介绍:

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

定义了一种简洁、自包含的格式,用于在通信双方以json数据格式安全的传输信息。

组成:

1.Header(头),记录令牌类型、签名算法等。例如:{"alg":"HS256","type":"JWT"}

2.Payload(有效载荷),携带一些自定义信息、默认信息等。例如:{"id":"1","username":"Tom"}

3.Signature(签名),放置Token被篡改、确保安全性。将header、payload融入,并加入指定秘钥,通过指定签名算法计算而来。

JWT令牌—生成/解析:

引入jjwt的依赖。

调用官方提供的工具类Jwts来生成或解析jwt令牌。

报错:JWT令牌被篡改或过期失效了

(注意事项:JWT校验时使用的签名秘钥,必须和生成JWT令牌时使用的秘钥是配套的)

   /**
     * 生成JWT令牌
     */
@Test
    public void testGenerateJwt(){
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("id",1);
        dataMap.put("username","admin");
​
​
        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256, "aXRoZWltYQ==")
                .addClaims(dataMap)
                .setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置过期时间
                .compact();
    System.out.println(jwt);
    }
​
/**
     * 解析令牌
     */
​
    @Test
    public void testParseJWT(){
        String token = "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJhZG1pbiIsImV4cCI6MTc0MDczMDEwNX0.BtOnJwrDgsAZTf3v-RJOhTwL7CESndEkl7gTU3XfgHU";
        Claims claims = Jwts.parser()
                .setSigningKey("aXRoZWltYQ==")//指定密钥
                .parseClaimsJws(token)//解析令牌
                .getBody();//获取自定义信息
        System.out.println(claims);
    }

登录功能(令牌)

生成token(令牌)

1.定义JWT令牌操作工具类。(基于ai)

2.登录完成后,调用工具类生成JWT令牌,并放回。

public class JwtUtils {
​
    private static String signKey = "SVRIRUlNQQ==";
    private static Long expire = 43200000L;
​
    /**
     * 生成JWT令牌
     * @return
     */
    public static String generateJwt(Map<String,Object> claims){
        String jwt = Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.HS256, signKey)
                .setExpiration(new Date(System.currentTimeMillis() + expire))
                .compact();
        return jwt;
    }
​
    /**
     * 解析JWT令牌
     * @param jwt JWT令牌
     * @return JWT第二部分负载 payload 中存储的内容
     */
    public static Claims parseJWT(String jwt){
        Claims claims = Jwts.parser()
                .setSigningKey(signKey)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
}

Service层代码修改:

/**
 * 登录
 */
@Override
public LoginInfo login(Emp emp) {
    //1.调用Mapper接口,根据用户名和密码查询员工信息
    Emp e = empMapper.selectByUsernamePassword(emp);
    //2.判断:判断是否存在这个员工,如果存在,组装登录信息
    if(e!=null){
        log.info("登录成功,员工信息:{}",e);
​
        //生成Jwt令牌
        Map<String, Object> claims = new HashMap<>();
        claims.put("id",e.getId());
        claims.put("username",e.getUsername());
        String jwt = JwtUtils.generateJwt(claims);
        return new LoginInfo(e.getId(),e.getUsername(),e.getName(),jwt);
    }
    //3.不存在,放回null
    return null;
}
过滤器(Filter):

概念:Filter过滤器,是javaWeb三大组件(Servlet、Filter、Listener)之一。

过滤器可以把对资源的请求拦截下来,从而实现一些特殊的功能。

过滤器一般完成一些通用的操作,比如:登录校验、统一编码处理、敏感字符处理等。

Filter快速入门:

1.定义Filter:定义一个类,实现Filter接口,并实现其所有方法。

2.配置Filter:Filter类上加@WebFilter注解,配置拦截路径。引导类上加@ServletComponentScan开启Servlet组件支持。

public class DemoFilter implements Filter {
    //初始化方法,web服务器启动的时候执行,只执行一次
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("拦截到了方法。。。。。");
​
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
​
    }
    //拦截到请求之后,执行,会执行多次
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("init 初始化方法。。。。");
    }
    //销毁方法,web服务器关闭的时候执行,只执行一次
    @Override
    public void destroy() {
        log.info("destroy 销毁方法。。。。");
    }

登录校验Filter:

@Slf4j
@WebFilter("/*")
public class TokenFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        //1.获取请求路径
        String requestURI = request.getRequestURI();
        //2.判断是否是登录请求,如果路径中包含/login,说明是登录操作,放行
        if(requestURI.contains("/login")){
            log.info("登录请求,放行");
            filterChain.doFilter(request,response);
        }
        //3.获取请求头中的token
        String token = request.getHeader("token");
        //4.判断token是否存在,如果不存在,说明用户没有登录,放回错误信息(响应401状态码)
        if(token == null||token.isEmpty()){
            log.info("令牌为空,响应401");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        //5.如果token存在,校验令牌,如果校验失败,放回错误信息(401状态码)
        try {
            JwtUtils.parseJWT(token);
        } catch (Exception e) {
            log.info("令牌非法,响应401");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        //6.校验通过,放行
        log.info("令牌合法,放行");
        filterChain.doFilter(request,response);
    }
}

详解(执行流程、拦截路径、过滤器链):

执行流程:先执行放行前逻辑,对应资源访问完成后,执行放行后逻辑。

拦截路径:

(Filter可根据需求,配置不同的拦截资源路径)

过滤器链:

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

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

拦截器Interceptor

快速入门:

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

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

//实现HandlerIntercepter
@Slf4j
@Component
public class DemoInterceptor implements HandlerInterceptor {
    //在目标资源方法运行之前运行- 返回值:true 放行,false 不放行
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle....");
        return true;
    }
​
    //在目标资源方法运行之后运行
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle");
    }
​
    //视图渲染完毕后运行
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion");
    }
}


//定义一个配置类实现WebMvcConfigurer接口,注册拦截器(/**)
/**
 * 配置类
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {
​
​
    @Autowired
    private DemoInterceptor demoInterceptor;
​
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(demoInterceptor).addPathPatterns("/**");//拦截所有请求
    }
}

令牌校验Interceptor:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    //1.获取请求路径
    String requestURI = request.getRequestURI();
    //2.判断是否是登录请求,如果路径中包含/login,说明是登录操作,放行
    if(requestURI.contains("/login")){
        log.info("登录请求,放行");
        return true;
    }
    //3.获取请求头中的token
    String token = request.getHeader("token");
    //4.判断token是否存在,如果不存在,说明用户没有登录,放回错误信息(响应401状态码)
    if(token == null||token.isEmpty()){
        log.info("令牌为空,响应401");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        return false;
    }
    //5.如果token存在,校验令牌,如果校验失败,放回错误信息(401状态码)
    try {
        JwtUtils.parseJWT(token);
    } catch (Exception e) {
        log.info("令牌非法,响应401");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        return false;
    }
    //6.校验通过,放行
    log.info("令牌合法,放行");
    return true;
}

详解:

拦截路径:(可根据需要配置拦截路径)

执行流程(过滤器和拦截器同时存在):

Filter和Interceptor区别:

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

2.拦截范围不同:过滤器Filter会拦截所有资源,而Interceptor只会拦截Spring环境中的资源

相关文章:

  • C++:类和对象(下篇)
  • INMP441数字全向麦克风介绍
  • 《React Hooks 入门与实战》
  • 网络知识点笔记,排查网络丢包问题
  • day02_Java基础
  • C++ 【右值引用】极致的内存管理
  • Kotlin 嵌套类和内部类
  • 链表:struct node *next;为什么用指针,为什么要用自身结构体类型?(通俗易懂)
  • 以太坊基金会换帅,资本市场砸盘
  • 【Java 后端】Restful API 接口
  • dify基础之prompts
  • 【计算机网络】常见tcp/udp对应的应用层协议,端口
  • IO与NIO的区别
  • set 和 map 的左右护卫 【刷题反思】
  • android::hardware::configureRpcThreadpool使用介绍
  • OpenCV计算摄影学(3)CUDA 图像去噪函数fastNlMeansDenoising()
  • Kubernetes (K8S) 高效使用技巧与实践指南
  • PyTorch 的 nn.NLLLoss:负对数似然损失全解析
  • 在 ASP.NET Core 中压缩并减少图像的文件大小
  • lqb官方题单-速成刷题清单(上) - python版
  • 网站flash代码/舟山seo
  • wordpress 打赏 手机/seo实战视频
  • 唐山seo优化/站长工具seo综合查询广告
  • vi设计网站大全/百度推广的效果
  • wordpress内部结构/开封网站优化公司
  • 制作网页怎样添加背景音乐/优化seo公司哪家好