conversational technology
Session: The user opens the browser, accesses the resources of the web server, and the session is established until one party disconnects and the session ends. A session can contain multiple requests and responses.
Session tracking: A method of maintaining browser state where the server needs to identify whether multiple requests are from the same browser in order to share data between multiple requests in the same session.
Session tracking solution:
Client session tracking technology: Cookies
Server-side session tracking technology: Session
Token technology
Session tracking solution comparison:
Cookies - Advantages: Technologies supported in the HTTP protocol
Disadvantages: Mobile APP cannot use cookies
Not safe, users can disable cookies themselves
Cookies cannot cross domains
Session-Advantages: stored on the server side, safe
Disadvantages: Session cannot be used directly in a server cluster environment
Disadvantages of Cookies
Advantages: Support PC and mobile terminals
Solving authentication issues in cluster environments
Reduce server-side storage pressure
Disadvantages: Need to implement it yourself
JWT token
Full name: JSON Web Token
Defines a concise, self-contained format for securely transmitting information in json data format between communicating parties. This information is reliable due to the presence of digital signatures.
composition:
The first part: Header (header), recording token type, signature algorithm, etc.
例如:{"alg":"HS256","type":"JWT"}
The second part: Payload (payload), carries some custom information, default information, etc.
例如:{"id":"1","usename":"Tom"}
The third part: Signature (signature), prevents Token from being tampered with and ensures security.
Add the header and payload to the specified key and calculate it through the specified signature algorithm.
JWT
Scenario: Login authentication
1. After successful login, generate a token
2. Each subsequent request must carry a JWT token. The system will verify the token before processing each request, and then process it after verification.
Introduce dependencies into pom.xml:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
@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, "itbignyi")
.setClaims(claims)
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))
.compact();
System.out.println(jwt);
@Test
public void testParseJwt() {
Claims claims = Jwts.parser()
.setSigningKey("itbignyi")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoidG9tIiwiaWQiOjEsImV4cCI6MTY5NDUzMjAwOH0.D4TjgQSvqZJlUNioEKxUn8euvxu9gqnSo4jfsJGuL7Q")
.getBody();
System.out.println(claims);
Note: The signing key used for JWT verification must match the key used for generating the JWT token.
If an error occurs when parsing and verifying the JWT token, it means that the JWT token has been tampered with or invalid, and the token is illegal.
Write the code:
FilterFilter
Concept: Filter filter is one of the three major components of JavaWeb (Servlet, Filter, Listener)
Filters can intercept requests for resources to achieve some special functions.
Filters generally complete some common operations, such as: login verification, unified encoding processing, processing of sensitive characters, etc.
Define Filter: define a class, implement the Filter interface, and override all its methods
Configure Filter: Add the @WebFilter annotation to the Filter class, configure the path to intercept resources, and add @ServletComponerntScan to the boot class to enable Servlet component support.
package com.itheima.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class DemoFilter implements 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 {
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
Filter interception path:
Filter can configure different interception resource paths according to needs:
Filter chain:
Introduction: In a web application, multiple filters can be configured, and these multiple filters form a filter chain.
Order: Annotate the configured Filter, the priority is based on the natural ordering of the filter class name (string)
Login verification
Login Verification Filter-Process:
1. Get the request URL 2. Determine whether the request URL contains login. If it does, indicate the login operation and allow it. 3. Get the token in the request header . 4. Determine whether the token exists. If it does not exist, return an error result. (Not logged in) 5. Parse the token. If the parsing fails, return an error result (Not logged in) 6. Release
package com.itheima.filter;
import com.alibaba.fastjson.JSONObject;
import com.itheima.pojo.Result;
import com.itheima.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import javax.imageio.spi.ServiceRegistry;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@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 res = (HttpServletResponse) servletResponse;
// 1.获取请求url
String url = req.getRequestURI().toString();
log.info("请求的url:{}", url);
// 2.判断请求url中是否包含login,如果包含,说明登录操作,放行
if (url.contains("login")) {
log.info("登录操作,放行...");
filterChain.doFilter(servletRequest,servletResponse);
return;
}
// 3.获取请求头中的令牌(token)
String jwt = req.getHeader("token");
// 4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
if (!StringUtils.hasLength(jwt)) {
log.info("请求头token,为空,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
String notLogin = JSONObject.toJSONString(error);
res.getWriter().write(notLogin);
return;
}
// 5.解析token,如果解析失败,返回错误结果(未登录)
try {
JwtUtils.pareJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析失败");
Result error = Result.error("NOT_LOGIN");
String notLogin = JSONObject.toJSONString(error);
res.getWriter().write(notLogin);
return;
}
// 6.放行
log.info("合法放行");
filterChain.doFilter(servletRequest, servletResponse);
}
}
Interceptor
Overview: It is a mechanism for dynamically intercepting method calls, similar to a filter. Provided by the Spring framework to dynamically intercept the execution of controller methods.
Function: intercept requests, execute preset code according to business needs before and after calling the specified method
Getting Started with Interceptor
1. Define the interceptor, implement the HandlerInterceptor interface, and rewrite all its methods
2. Register interceptor
package com.itheima.config;
import com.itheima.interceptor.LoginCheckInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration //配置类
public class WebConfig implements WebMvcConfigurer {
@Autowired
private LoginCheckInterceptor loginCheckInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
}
}
package com.itheima.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return HandlerInterceptor.super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
}
}
Interceptor - interception path
The interceptor can configure different interception paths according to needs.
Interceptor-execution process
Filter and Interceptor
The interface scope is different: the filter needs to implement the Filter interface, and the interceptor needs to implement the HandlerInterceptor interface
The interception scope is different: Filter will intercept all resources, while Interceptor will only intercept resources in the Spring environment.
Run the code:
package com.itheima.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.itheima.pojo.Result;
import com.itheima.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
// 1.获取请求url
String url = req.getRequestURI().toString();
log.info("请求的url:{}", url);
// 2.判断请求url中是否包含login,如果包含,说明登录操作,放行
if (url.contains("login")) {
log.info("登录操作,放行...");
return true;
}
// 3.获取请求头中的令牌(token)
String jwt = req.getHeader("token");
// 4.判断令牌是否存在,如果不存在,返回错误结果(未登录)
if (!StringUtils.hasLength(jwt)) {
log.info("请求头token,为空,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
String notLogin = JSONObject.toJSONString(error);
res.getWriter().write(notLogin);
return false;
}
// 5.解析token,如果解析失败,返回错误结果(未登录)
try {
JwtUtils.pareJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析失败");
Result error = Result.error("NOT_LOGIN");
String notLogin = JSONObject.toJSONString(error);
res.getWriter().write(notLogin);
return false;
}
// 6.放行
log.info("合法放行");
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 {
}
}
Exception handling
Global exception handler
package com.itheima.exception;
import com.itheima.pojo.Result;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionhandler {
@ExceptionHandler(Exception.class)
public Result ex(Exception ex) {
ex.printStackTrace();
return Result.error("操作失败,联系管理员");
}
}