赞
踩
目录
接口信息:
请求参数:
响应数据:
- @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);
-
- return e != null? Result.success():Result.error("用户名或密码错误!");
-
- }
- }
由于是校对员工用户名和密码,所以用empservice层和empmapper层就好
- //员工登录
- Emp login(Emp emp);
- //员工登录
- @Override
- public Emp login(Emp emp) {
-
- return empmapper.getByUsernameAndPassword(emp);
- }
- //员工登录
- @Select("select * from emp where username = #{username} and password = #{password}")
- Emp getByUsernameAndPassword(Emp emp);
- 会话:一次会话中包含多次请求和响应
- 会话跟踪:服务器需要识别多次请求是否来自同一浏览器,以便在同一次会话的多次请求中共享数据
- 优点:HTTP协议支持的技术
- 缺点:
- 移动端APP不支持
- 不安全,用户可以禁用Cookie
- Cookie不可以跨域
- 优点:存储在服务端,安全
- 缺点:
- 服务器集群环境下无法直接使用Session
- Cookie的缺点
- 优点:
- 支持PC端,移动端
- 解决集群环境下的认证问题
- 减轻服务器端存储压力
- 缺点:
- 需要自己实现
- 概念:JWT就是将json格式的数据以安全的形式封装
- 组成:
- 第一部分——头:记录令牌类型、签名算法等。【eg:"alg":"HS256","type":"Tom"】
- 第二部分——有效载荷:携带一些自定义信息、默认信息。【eg:"id":"1"】
- 第三部分——签名:防止Token被篡改,保证安全性。将头、有效载荷并加入指定密钥,提高指定签名算法计算得来。
- <!--JWT令牌-->
- <dependency>
- <groupId>io.jsonwebtoken</groupId>
- <artifactId>jjwt</artifactId>
- <version>0.9.1</version>
- </dependency>
- // 测试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)) //设置有效期为1h
- .compact();
-
- System.out.println(jwt);
- }
生成令牌
eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVG9tIiwiaWQiOjEsImV4cCI6MTY5ODA2OTAxNX0.hjkFgUORQs1DOnaZa4A2n_5jDVLxkLO89i3Ri5D7LqA
在官网可以查到令牌的原数据
- //解析jwt令牌
- @Test
- public void testParseJwt()
- {
- Claims claims = Jwts.parser()
- .setSigningKey("itheima") //密钥
- .parseClaimsJws("eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVG9tIiwiaWQiOjEsImV4cCI6MTY5ODA2OTAxNX0.hjkFgUORQs1DOnaZa4A2n_5jDVLxkLO89i3Ri5D7LqA")
- .getBody();
- System.out.println(claims);
- }
- package com.itroye.utils;
-
- import io.jsonwebtoken.Claims;
- import io.jsonwebtoken.Jwts;
- import io.jsonwebtoken.SignatureAlgorithm;
- import java.util.Date;
- import java.util.Map;
-
- public class JwtUtils {
-
- private static String signKey = "itheima";
- private static Long expire = 43200000L; //规定过期时间为12h
-
- /**
- * 生成JWT令牌
- * @param claims JWT第二部分负载 payload 中存储的内容
- * @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;
- }
- }
- @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("用户名或密码错误!");
-
- }
- }
step 1:新建filter包+类
step 2:过滤器代码编写
注意是:选javax.servlet这个!
选中接口名并alt+enter自动生成接口中的三个方法
@WebFilter(urlPatterns = "/*") public class DemoFilter implements Filter { @Override //初始化的方法 只调用一次 public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化方法执行了"); } @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("销毁方法执行了"); } }其中注解@WebFilter(urlPatterns = "/*") 是拦截路径,而要使用它,需要在启动类上添加
@ServletComponentScan //开启对Servlet组件的支持
浏览器发出请求——过滤器执行放行前的逻辑——放行——login、depts(访问web资源)——放行之后的逻辑——响应给浏览器
拦截路径 url值 含义 拦截具体路径 /login 只有访问/login路径,才会被拦截 目录拦截 /emps/* 访问/emps下所有资源时,都会被拦截 拦截所有 /* 访问所有资源都会被拦截
可以设置多个过滤器,形成过滤器链
- 过滤器的执行先后顺序是根据过滤器类名(字符串)的自然排序,也就是说AbcFilter在DemoFilter过滤器之前
- 第一个过滤器放行后进入第二个过滤器
- 登录成功后,生成一个jwt令牌并返回给前端,前端将该jwt令牌记录(在请求头token中携带令牌),并在后续每一次请求中携带到服务端
- 过滤器校验jwt令牌的有效性,进行拦截放行操作
① 手动转换JSON——fastJSON
注意:之前在Controller里直接返回Result.success(),因为在注释@RestController下,会自动将返回值转换为json格式,而在过滤器类中,没有该注解,因此需要手动转换成json格式
这里我们用到阿里巴巴提供的fastJSON
首先在pom.xml文件中引入fastJSON依赖
<!--fastJSON--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency>
- @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;
-
- //1、获取请求url
- String url = req.getRequestURL().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("请求头为空,返回为登录信息");
- Result error = Result.error("NOT_LOGIN");
- // 手动转换成JSON --阿里巴巴fastJSON
- String notLogin = JSONObject.toJSONString(error);
- resp.getWriter().write(notLogin);
- //上面的流程:将错误信息封装在Result中-->转换为json格式-->response的write()方法将错误信息返回给浏览器
- return;
- }
-
- //5、解析token,如果解析失败,返回错误结果(未登录)
- try{
- JwtUtils.parseJWT(jwt); //解析报错 说明令牌错误
- }catch (Exception e)
- {
- e.printStackTrace();
- log.info("解析令牌失败,返回错误信息");
- // 返回错误信息丝滑小连招
- Result error = Result.error("NOT_LOGIN");
- String notLogin = JSONObject.toJSONString(error);
- resp.getWriter().write(notLogin);
- return;
- }
-
- //6、放行
- log.info("令牌合法,放行!");
- filterChain.doFilter(servletRequest,servletResponse);
- }
- }
此时,当我们在网页访问depts、emps时,如果没有登录,页面会强制跳转到登录页面,只有合法登录,获取到合法令牌,才能访问后台
step 1:新建interceptor包+类
step 2:拦截器代码编写
ctrl+o调出面板,选中三个默认方法
- @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("postHandle运行了");
- }
-
- @Override // 视图渲染完毕后运行 最后运行
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
- System.out.println("afterCompletion运行了");
- }
- }
- addPathPatterns("/**") ———— 拦截
- excludePathPatterns("/login") ———— 不拦截
首先连包带类创建一个配置类
@Configuration //配置类 public class WebConfig implements WebMvcConfigurer { @Autowired private LoginCheckInterceptor loginCheckInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**"); } }
先执行过滤器,然后再执行拦截器
拦截路径 含义 举例 /* 一级路径 能匹配/depts、/emps、/login,不能匹配/depts/1 /** 任意路径 都可以 /depts/* /depts下的一级路径 可以匹配/depts/1,不能匹配/depts/1/2
/depts/** /depts下的任意路径 不能匹配/emps/1
- 过滤器会拦截所有资源
- 拦截器只会拦截spring环境的资源
- @Slf4j
- @Component //交给ioc容器管理
- public class LoginCheckInterceptor implements HandlerInterceptor {
- @Override // 目标资源方法运行【前】运行 true:放行 false:拦截
- public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
- System.out.println("preHandle运行了");
-
- //1、获取请求url
- String url = req.getRequestURL().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("请求头为空,返回为登录信息");
- Result error = Result.error("NOT_LOGIN");
- // 手动转换成JSON --阿里巴巴fastJSON
- String notLogin = JSONObject.toJSONString(error);
- resp.getWriter().write(notLogin);
- //上面的流程:将错误信息封装在Result中-->转换为json格式-->response的write()方法将错误信息返回给浏览器
- return false;
- }
-
- //5、解析token,如果解析失败,返回错误结果(未登录)
- try{
- JwtUtils.parseJWT(jwt); //解析报错 说明令牌错误
- }catch (Exception e)
- {
- e.printStackTrace();
- log.info("解析令牌失败,返回错误信息");
- // 返回错误信息丝滑小连招
- Result error = Result.error("NOT_LOGIN");
- String notLogin = JSONObject.toJSONString(error);
- resp.getWriter().write(notLogin);
- return false;
- }
-
- //6、放行
- 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运行了");
- }
- }
step1:连包带类创建异常类
step2:编写代码
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) //定义捕获所有类型的异常 public Result ex(Exception ex) { ex.printStackTrace(); return Result.error("对不起,操作失败,请联系管理员"); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。