目录
1.基础登陆功能
2.登陆校验
由于在没有进行登陆的情况下也可以进行部门管理员工管理的操作,所以需要进行登陆校验。
3.登陆认证
3.1登陆校验--会话技术
会话技术是获取登陆标记的一种传统方式,用户登陆成功之后在每一次请求中,都会得到该标记。
登录操作是一次请求响应,后面执行的操作也是请求响应,在后面的请求当中需要拿到当前登录的 数据,所以要在一次会话的多次请求之间来共享数据,也就是会话跟踪。
3.2登陆校验--会话跟踪方案一
Cookie是客户端会话跟踪技术,储存在客户端浏览器。使用Cookie进行会话跟踪,可以在浏览器向服务器发起第一次请求时设置一个Cookie。比如在浏览器第一次请求登陆接口时,登陆接口执行完成之后就可以设置一个Cookie用于存储相关的信息如当前登陆用户的用户名及其信息,服务器向浏览器响应数据时,就将这个Cookie自动相应回去;浏览器接收到响应的数据时就会自动将数据储存在本地;在后续的请求当中浏览器会自动将数据携带到服务器端。自动进行的原因是因为Cookie是HTTP协议当中支持的技术,浏览器产商支持这一标准,HTTP协议当中就为此提供了一个响应头SetCookie以及一个请求头Cookie。
服务器端发送给浏览器的响应头用来设置Cookie,接收到的请求头用来接收浏览器端发送的请求携带存储的Cookie。
import com.study.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 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();
}
}
跨域:在前后端分离的开发模式下,前端程序与后端程序独立部署,当前所处的位置以及请求的位置只要协议,IP地址,端口号任意一个不相同就是跨域,比如要访问前端页面执行登录操作就要访问另一个IP地址
3.3登陆校验--登陆跟踪方案二、三
Seesion是存储在服务器端的会话技术 ,底层基于Cookie 。基于Session进行会话跟踪,在浏览器第一次进行请求的时候可以直接在服务器端获取会话对象Session,但是第一次请求时Session对象不存在,服务器会自动的创建一个会话对象Session,且每一个会话对象都有一个id(Session的id)。服务器端在给浏览器端响应数据的时候将Session的id通过Cookie响应给浏览器,也就是在响应头当中增加了一个SetCookie响应头,浏览器接收到响应数据之后会自动的将Cookie存储在浏览器本地。在后续的每一次请求当中都会将Cookie的数据获取出来并且携带到服务端。服务器端拿到Session的值也就是Session的id之后,就会从众多的Session当中找到当前请求对应的会话对象。这样就可以通过Session会话对象在同一次会话的多次请求之间来共享数据。
令牌也就是用户身份的标识(字符串),浏览器发起请求请求登录接口的时候若登陆成功就生成一个令牌,在响应数据的时候就可以将这个身份响应给前端,前端接收到令牌之后可以将其保存起来,可以存在Cookie或其他的存储空间当中,在后续的每一次请求当中都需要将这个令牌携带到服务器端,校验令牌的有效性。如果是在同一个会话的多次请求当中共享数据,就可以将要共享的数据存在令牌当中。
4.登陆校验
4.1JWT令牌--介绍
JWT令牌个人理解也就是将JSON的数据格式通过编码加密为字符串。Header部分以及PayLoad部分都是将JSON数据通过BASE64编码转化得来的,Signature部分是通过签名算法得来的。
浏览器发起请求执行登录操作访问登陆的接口,登录成功生成一个JWT令牌。之后将生成的JWT令牌返回给前端,前端拿到JWT令牌之后就会自动存储起来,在后续的每一次请求当中都会将JWT令牌携带到服务器端,服务端就要进行统一拦截,先判断有没有将该令牌带过来,再判断令牌是否有效
4.2JWT令牌--生成与校验
要使用JWT令牌就要引入JWT依赖。
/**
* 测试生成JWT令牌
*/
@Test
public void testGenJWT() {
Map<String, Object> claims = new HashMap<>();
claims.put("id",1);
claims.put("name","jane");
String jwt = Jwts.builder()
.signWith(SignatureAlgorithm.HS256, "rayjane")//签名算法
.setClaims(claims)//自定义内容(载荷)
.setExpiration(new Date(System.currentTimeMillis() + 3600 * 1000))//设置有效期为1h
.compact();
System.out.println(jwt);
}
/**
* 解析JWT
*/
@Test
public void testParseJWT() {
Claims claims = Jwts.parser()
.setSigningKey("rayjane")
.parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiamFuZSIsImlkIjoxLCJleHAiOjE2OTMxNjI1Nzd9.4Az5KOYGuXxvVAL1EJ2l4fjw2VSyzCvkPhqPtAurvDM")
.getBody();
System.out.println(claims);
}
4.3JWT令牌--登录后下发令牌
4.4Filter--入门
4.5Fliter--详解(执行流程-拦截路径)
4.6Fliter--详解(过滤器链)
4.7Fliter--登陆校验过滤器
import com.alibaba.fastjson.JSONObject;
import com.study.pojo.Result;
import com.study.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
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 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-->阿里巴巴fastjson
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return;
}
//解析token,如果解析失败,返回错误信息
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析令牌失败,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
//手动操作,对象转为JSON-->阿里巴巴fastjson
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return;
}
//放行
log.info("令牌合法,放行");
filterChain.doFilter(servletRequest,servletResponse);
}
}
4.8Interceptor--入门
4.9Interceptor--详解
4.10Interceptor--登陆校验拦截器
import com.alibaba.fastjson.JSONObject;
import com.study.pojo.Result;
import com.study.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 //目标资源执行之前运行 ,返回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-->阿里巴巴fastjson
String notLogin = JSONObject.toJSONString(error);
resp.getWriter().write(notLogin);
return false;
}
//解析token,如果解析失败,返回错误信息
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析令牌失败,返回未登录的信息");
Result error = Result.error("NOT_LOGIN");
//手动操作,对象转为JSON-->阿里巴巴fastjson
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("postHandle....");
}
@Override //视图渲染完毕之后运行 最后运行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion...");
}
}
4.11异常处理
import com.study.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("对不起,非法操作,请联系管理员!");
}
}