JavaWeb学习路线(8)——登录

一、基本登录功能

(一)需求: 根据账号与密码判别用户是否可以登录

(二)实现步骤

  • Controller接收传递的JSON格式数据,使用@RequestBody+实体类进行接收,调用Service具体处理。
  • Service创建登录接口,实现类调用Mapper根据条件查询是否存在具体用户,存在则返回具体用户,反之返回null。
  • Mapper创建条件查询接口,利用条件查询SQL查询用户。

(三)代码实现
UserController.java

@RestController //@Controller+@ResponseBody
public class LoginCtroller{
    
    
	@PostMapping("/login")
    public int login(@RequestBody User user){
    
    
        User u = userService.login(user);
        return u !=null?200:-1;
    }
}

UserService.java

public interface UserService {
    
    
    User login(User user);
}

UserServiceImpl.java

@Service
public class UserServiceImpl implements UserService{
    
    

    @Autowired
    private UserMapper userMapper;

    @Override
    public User login(User user) {
    
    
        return userMapper.getUserByUsernameAndPassword(user);
    }
}

UserMapper.java

@Mapper
public interface UserMapper {
    
    
    @Select("select * from user where username = #{username} and password = #{password}")
    User getUserByUsernameAndPassword(User user);
}

(四)现有登录的缺陷

  • 无法限制用户直接访问内容页。

二、登录校验

(一)概念: 每一次请求都要进行用户登录授权。

(二)登录校验相关技术
在这里插入图片描述

1、登录标记: 一般采用会话技术,在用户登录成功后,每一次请求中都会获取该标记。

2、统一拦截: 两种方式

  • 过滤器 Filter
  • 拦截器 Interceptor

(三)会话技术

1、概念

  • 会话: 用户打开浏览器,访问we服务器的资源,会话建立,直到一方断开连接,会话结束。在一次会话中可以多次请求和响应。
  • 会话跟踪: 一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据
  • 会话跟踪方案:
    • 客户端会话跟踪技术—— Cookie
    • 服务端会话跟踪技术—— Session
    • 令牌技术

2、客户端会话跟踪 Cookie

(1)Cookie使用过程:

  • 用户登录成功后,服务器创建Cookie并自动发送给浏览器
  • 浏览器接收Cookie并自动存储在浏览器本地
  • 用户使用浏览器向服务器发送请求,浏览器自动将Cookie请求头(Set-Cookie: name=value)发送到服务器的同一拦截层进行校验,校验通过后处理请求。

模拟Cookie在服务器端的操作

@Slf4j
@RestController
public class SessionController {
    
    
    @GetMapping("/c1")
    public int cookie1(HttpServletResponse response){
    
    
        response.addCookie(new Cookie("login_username","zengoo"));
        return 200;
    }

    @GetMapping("/c2")
    public int cookie(HttpServletRequest request){
    
    
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie : cookies) {
    
    
            if (cookie.getName().equals("login_username")) System.out.println("用户登录的账号为 " + cookie.getValue());
        }
        return 200;
    }
}

执行C1方法请求到服务器效果图
在这里插入图片描述

执行C2方法,获取指定的Cookie内容效果图

在这里插入图片描述

(2)Cookie的优缺点

  • 优点
    • HTTP协议支持的技术
  • 缺点
    • 移动端无法使用Cookie
    • 不安全,用户可以禁用Cookie
    • Cookie不支持跨域

3、服务器会话跟踪技术 Session

(1)Session的使用过程

  • 用户登录成功后常见Session会话,通过Cookie记录SessionID并发送给浏览器
  • 浏览器接收Cookie并存储到本地
  • 当发生请求服务器时,SessionID发送到服务器,服务器查找对应Session进行连接。

(2)模拟Session

@Slf4j
@RestController
public class SessionController {
    
    
    @GetMapping("/s1")
    public int session1(HttpSession session){
    
    
        log.info("HttpSession-s1:{}",session.hashCode());
        session.setAttribute("login_account","tom1101");
        return 200;
    }

    @GetMapping("/s2")
    public int session2(HttpSession session){
    
    
        log.info("HttpSession-s2:{}",session.hashCode());
        Object user = session.getAttribute("login_account");
        log.info("user:{}",user);
        return 200;
    }
}

设置session效果图

在这里插入图片描述
服务端获取Session会话效果图

在这里插入图片描述
(3)Session的优缺点

  • 优点
    • 存储在服务器端,安全性高
  • 缺点
    • 服务器集群环境下无法使用Session(原因是产生Session的服务器与服务分配的服务器可能不是同一台)
    • Cookie的缺点(Session的底层是Cookie)

4、令牌技术

(1)令牌技术的使用过程

  • 用户登录成功后获取从服务器端获取以个令牌(例如token,accessKey…),服务器返回给浏览器
  • 浏览器接收令牌并存储在本地(使用Cookie或Session都可以)
  • 当发生请求服务器时,浏览器发送令牌给服务器,服务器进行校验后处理请求

(2)令牌技术的优缺点

  • 优点
    • 支持PC、移动
    • 解决集群环境下的认证问题
    • 减轻服务器存储压力
  • 缺点
    • 需要手动实现(生成、存储等过程)

(3)JWT令牌技术

  • 简介
    • 全称: JSON Web Token(官网:https://jwt.io/
    • 作用: 定义了一种简洁的(JWT是字符串)、自包含(可以插入自定义的数据)的格式,用于在通信双方以JSON数据格式安全的传输信息。由于数字签名的存在,这些信息是可靠的。
    • 结构:
      • 第一部分:Header(头),记录令牌类型,签名算法等。例如 {“alg”:“HS256”,“type”:“JWT”}
      • 第二部分:Payload(有效载荷),自定义的内容、默认信息等。例如 {“id”:“1”,“username”:“Tom”}
      • 第三部分:Signature(签名),防止Token被篡改、确保安全性。将header、payload,并加入指定密钥,通过指定签名算法计算而来。
    • JWT使用
      • 引入JWT依赖。io.jsonwebtoken.jjwt - 0.9.1
    • 使用JWT的注意事项
      • JWT校验时必须使用对应的签名密钥
      • JWT令牌失效的原因:
        • 令牌被篡改
        • 令牌到期

生产JWT

public class DataTest {
    
    
    @Test
    public void getJWT(){
    
    
        //载荷内容
        Map<String,Object> claims = new HashMap<>();
        claims.put("id",1);
        claims.put("username","tom");

        String jwt = Jwts.builder()
                .signWith(SignatureAlgorithm.HS256,"zengoo")//签名算法Base64+签名密钥"zengoo"
                .setClaims(claims) //载荷
                .setExpiration(new Date(System.currentTimeMillis()+ (12*3600*1000))) //有效期
                .compact();
                
        System.out.println(jwt);
    }
}

/*打印结果*/
eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjg4MDYzMzUwLCJ1c2VybmFtZSI6InRvbSJ9.occWRYeyio23As2Xd0RilmZtASE3wF0bYc_6F3OFE-M

解析令牌

    @Test
    public void parseJWT(){
    
    
        Claims claim = Jwts.parser()
                .setSigningKey("zengoo") //签名密钥
                .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjg4MDYzMzUwLCJ1c2VybmFtZSI6InRvbSJ9.occWRYeyio23As2Xd0RilmZtASE3wF0bYc_6F3OFE-M") //JWT内容
                .getBody();
        System.out.println(claim);
    }
/*打印输入*/
{
    
    id=1, exp=1688063350, username=tom}

(四)Filter 过滤器

1、简介

  • 概念: Filter 过滤器,是JavaWeb 三大组件(Servlet、Filter、Listener)之一。
  • 作用: 过滤器可以把资源的请求拦截下来,完成通用操作,例如:登录校验、统一编码处理、敏感词字符处理等。

2、使用

(1)定义Filter: 定义一个类,实现Filter接口,并重写方法。

@WebFilter(urlPatterns = "/*") //拦截所有请求
public class LoginFilter implements Filter {
    
    
    //初始化方法,web服务器启动,创建Filter时调用,仅调用一次
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    
        Filter.super.init(filterConfig);
    }
    //对请求方法进行拦截处理,可多次调用
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
        //处理代码
        System.out.println("拦截方法执行");
        //放开请求
        filterChain.doFilter(servletRequest,servletResponse);
    }

    //销毁方法,服务器关闭时调用,仅调用一次
    @Override
    public void destroy() {
    
    
        Filter.super.destroy();
    }
}

(2)配置Filter: Filter类加上 @WebFilter注解,配置拦截资源的路径,启动类上加 @ServletComponentScan注解,开启Servlet组件支持。

@ServletComponentScan //开启Servlet组件扫描
@SpringBootApplication
public class SpringbootMybatisApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(SpringbootMybatisApplication.class, args);
    }
}

3、过滤器的细节问题

(1)执行流程

  • web服务器启动,过滤器启动初始化方法init
  • 浏览器发送任意一个请求给web服务器,过滤器拦截该请求
  • 过滤器启动doFilter方法判别请求或处理请求内容,确认无误后提交给FilterChain类的doFilter()方法放开请求访问资源。
  • 若还有需要处理的逻辑,则可在放开请求后编写执行。

(2)拦截路径

  • 常见拦截路径
路径方式 举例 说明
具体路径 /login 访问 /login 时拦截
目录拦截 /userAPI/* 访问 /userAPI 下的资源时拦截
拦截所有 /* 访问所有资源都会被拦截

(3)过滤器链

  • 概念: 一个web应用中,可配置多个过滤器,多个过滤器形成的过滤通道形成了一个过滤链。
  • 作用: 按照类名顺序通过过滤器链,服务器端可以通过多个过滤器进行多次额外加工。

(五)Interceptor 拦截器

1、简介

  • 概念: Spring框架中提供的一种动态拦截方法调用的机制,类似于过滤器,所以拦截器的作用范围是整个Spring框架,其它的资源不进行拦截。
  • 作用: 拦截请求,在指定的方法调用前后,根据业务需求执行预先设定的代码。

2、使用拦截器
(1)定义拦截器: 实现HandlerInterceptor 接口,并重写所有方法

@Component
public class LoginInterceptor implements HandlerInterceptor {
    
    
    @Override   //Controller之前执行,true——放开拦截;false——不放开
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
    
        System.out.println("前期处理");
        return true;
    }

    @Override   //Controller之后执行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    
    
        System.out.println("请求被拦截");
    }

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

(2)注册拦截器

@Configuration
public class LoginConfig implements WebMvcConfigurer {
    
    
    @Autowired
    private LoginInterceptor loginInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
    	//注册拦截器并配置拦截路径与非拦截路径
        registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/loign");
    }
}

3、拦截器的细节问题

(1)执行流程

  • web服务器启动,先启动Filter类init()方法。
  • 浏览器发送请求,服务器接收请求后过滤器Filter先进行拦截,通过前端控制器DispatcherServlet转发给拦截器Interceptor,在请求进入控制器Controller前对数据进行处理,判断可放开后,请求进入资源访问。
  • 请求访问资源完毕后,返回拦截器进行加工,再转发给前端控制器,再转发给过滤器,最终返回到浏览器。

在这里插入图片描述

(2)拦截路径

  • 常见拦截路径
路径方式 举例 说明
一级路径 /* 拦截/login,/list,不能拦截 /depts/1
任意拦截 /** 全路径拦截
某一路径下的一级路径 /depts/* 能拦截 /depts/1,不能拦截 /depts/1/2 ,/depts
某一路径下的所有路径 /depts/** 能拦截 /depts下的所有路径

(六)过滤器与拦截器的区别

  • 接口规范: 过滤器 —— Filter;拦截器 —— HandlerInterceptor
  • 拦截范围: 过滤器—— 拦截所有资源 ; 拦截器 —— 拦截Spring环境下的资源

三、异常处理

两种解决方案

  • 方案一: 在Controller的所有方法中进行try…catch处理
  • 方案二: 定义全局异常处理器

(一)异常处理器的使用

1、定义异常处理器

@RestControllerAdvice   //声明控制器异常处理,相当于@ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {
    
    
    //统一进行异常处理,并向浏览器返回异常结果
    @ExceptionHandler(Exception.class)	//定义捕获的异常类型 Exception是所有异常的父类
    public int ex(Exception ex){
    
    
        ex.printStackTrace();
        return 500;
    }
}

猜你喜欢

转载自blog.csdn.net/Zain_horse/article/details/131450435
今日推荐