网站名称收录,产品网站设计理念,网站ftp密码怎么修改,北京市住房和城乡建设部网站官网登录功能
需求分析 在登录界面中#xff0c;输入用户的用户名以及密码#xff0c;然后点击 “登录” #xff0c;服务端判断用户输入的用户名和密码是否都正确。如果正确#xff0c;则返回成功结果#xff0c;前端跳转至系统首页面#xff1b;否则报错#xff0c;停留在…登录功能
需求分析 在登录界面中输入用户的用户名以及密码然后点击 “登录” 服务端判断用户输入的用户名和密码是否都正确。如果正确则返回成功结果前端跳转至系统首页面否则报错停留在登录界面。
接口文档
请求路径/login
请求方式POST
接口描述该接口用于员工登录Tlias智能学习辅助系统登录完毕后系统下发JWT令牌。请求参数参数格式application/json
请求数据样例{username: jinyong,password: 123456}响应数据参数格式application/json
响应数据样例{code: 1,msg: success,data:eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo}请求参数参数说明 . 请求参数参数说明
思路分析 登录服务端的核心逻辑就是接收前端请求传递的用户名和密码 然后再根据用户名和密码查询用户信息如果用户信息存在则说明用户输入的用户名和密码正确。如果查询到的用户不存在则说明用户输入的用户名和密码错误。
功能开发
LoginController
Slf4j
RestController
public class LoginController {Autowiredprivate 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
// 用户登录
Emp login(Emp emp);EmpServiceImpl
Override
public Emp login(Emp emp) {//调用dao层功能登录Emp loginEmp empMapper.getByUsernameAndPassword(emp);//返回查询结果给Controllerreturn loginEmp;
}EmpMapper
Select(select id, username, password, name, gender, image,job, entrydate, dept_id, create_time, update_time from empf where username#{username} and password #{password})
Emp getByUsernameAndPassword(Emp emp);功能测试 登录校验
会话技术 在web开发当中会话指的是浏览器与服务器之间的一次连接。 需要注意的是会话和浏览器是关联的。 会话跟踪是一种维护浏览器状态的方法服务器需要识别多次请求是否来自于同一浏览器以便在同一次会话的多次请求间共享数据。
会话跟踪技术有两种Cookie客户端会话跟踪技术即数据存储在客户端浏览器当中Session服务端会话跟踪技术即数据存储在储在服务端传统的会话跟踪技术在现在的开发当中存在很多的问题。 为了解决这些问题在现在开发中基本上都会采用第三种方案通过令牌技术来进行会话跟踪。
JWT令牌
JWT介绍 JWT全称JSON Web Token定义了一种简洁的、自包含的格式用于在通信双方以 json 数据格式安全的传输信息。
JWT的组成 JWT令牌由三个部分组成三个部分之间使用英文的点来分割第一部分Header(头 记录令牌类型、签名算法等。 例如{alg:HS256,type:JWT}第二部分Payload(有效载荷携带一些自定义信息、默认信息等。 例如{id:1,username:Tom}第三部分Signature(签名防止Token被篡改、确保安全性。将header、payload并加入指定秘钥通过指定签名算法计算而来。JWT令牌最典型的应用场景就是登录认证 1. 在浏览器发起登录请求此时会访问登录接口如果登录成功则会生成一个jwt令牌并将生成的 jwt令牌返回给前端。 2. 前端拿到jwt令牌之后会将jwt令牌存储起来。在后续的每一次请求中都会将jwt令牌携带到服务端。 3. 服务端统一拦截请求之后先判断请求有没有携带令牌如果没有则直接拒绝访问如果有还需要校验一下令牌是否是有效有效则直接放行进行请求的处理。
在JWT登录认证整个流程当中涉及到两步操作1. 在登录成功之后生成令牌。2. 每一次请求当中要接收令牌并对令牌进行校验。生成jwt令牌 JWT的依赖
!-- JWT依赖 --
dependencygroupIdio.jsonwebtoken/groupIdartifactIdjjwt/artifactIdversion0.9.1/version
/dependency生成JWT代码
Test
public void genJwt(){MapString,Object claims new HashMap();claims.put(id,1);claims.put(username,Tom);String jwt Jwts.builder().setClaims(claims) //自定义内容(载荷).signWith(SignatureAlgorithm.HS256, itheima) //签名算法.setExpiration(new Date(System.currentTimeMillis() 24*3600*1000)) //有效期.compact();System.out.println(jwt);
}校验jwt令牌 解析生成的令牌
Test
public void parseJwt(){Claims claims Jwts.parser()//指定签名密钥必须保证和生成令牌时使用相同的签名密钥.setSigningKey(itheima).parseClaimsJws(eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjcyNzI5NzMwfQ.fHi0Ub8npbyt71UqLXDdLyipptLgxBUg_mSuGJtXtBk).getBody();System.out.println(claims);
}在使用JWT令牌时需要注意JWT校验时使用的签名秘钥必须和生成JWT令牌时使用的秘钥是配套的。如果JWT令牌解析校验时报错则说明JWT令牌被篡改或失效了令牌非法。登录下发令牌
通过JWT令牌技术来跟踪会话主要是两步操作1. 生成令牌2. 校验令牌 JWT令牌怎么返回给前端呢主要看接口文档中关于登录接口的描述的响应数据
响应数据参数格式application/json
响应数据样例{code: 1,msg: success,data:eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo}响应数据参数说明
过滤器Filter 怎么判断统一拦截到所有的请求校验令牌的有效性呢有两种解决方案1. Filter过滤器、2. Interceptor拦截器 Filter过滤器是 JavaWeb三大组件(Servlet、Filter、Listener)之一。过滤器可以把对资源的请求拦截下来从而实现一些特殊的功能。使用了过滤器之后要想访问web服务器上的资源必须先经过滤器过滤器处理完毕之后才可以访问对应的资源。过滤器一般完成一些通用的操作比如登录校验、统一编码处理、敏感字符处理等。
Filter快速入门
过滤器的基本使用操作第1步定义过滤器 1.定义一个类实现 Filter 接口并重写其所有方法。第2步配置过滤器Filter类上加 WebFilter 注解配置拦截资源的路径。引导类上加ServletComponentScan 开启Servlet组件支持。定义过滤器
//定义一个类实现一个标准的Filter过滤器的接口
public class DemoFilter implements Filter {Override //初始化方法, 只调用一次public void init(FilterConfig filterConfig) throwsServletException {System.out.println(init 初始化方法执行了);}Override //拦截到请求之后调用, 调用多次public void doFilter(ServletRequest request, ServletResponseresponse, FilterChain chain) throws IOException, ServletException {System.out.println(Demo 拦截到了请求...放行前逻辑);//放行chain.doFilter(request,response);}Override //销毁方法, 只调用一次public void destroy() {System.out.println(destroy 销毁方法执行了);}
}Filter的配置
WebFilter(urlPatterns /*) //配置过滤器要拦截的请求路径 /* 表示拦截浏览器的所有请求
public class DemoFilter implements Filter {Override //初始化方法, 只调用一次public void init(FilterConfig filterConfig) throwsServletException {System.out.println(init 初始化方法执行了);}Override //拦截到请求之后调用, 调用多次public void doFilter(ServletRequest request, ServletResponseresponse, FilterChain chain) throws IOException, ServletException {System.out.println(Demo 拦截到了请求...放行前逻辑);//放行chain.doFilter(request,response);}Override //销毁方法, 只调用一次public void destroy() {System.out.println(destroy 销毁方法执行了);}
}在Filter类上面加了WebFilter注解之后还需要在启动类上面加上一个注解ServletComponentScan通过这个ServletComponentScan注解来开启SpringBoot项目对于Servlet组件的支持。
ServletComponentScan
SpringBootApplication
public class SpringbootWebExampleApplication {public static void main(String[] args) {SpringApplication.run(SpringbootWebExampleApplication.class, args);}}Filter详解
过滤器的执行流程 过滤器拦截到请求后如果要继续访问后面的web资源则需要执行放行操作即调用 FilterChain对象当中的doFilter()方法。在放行后访问完 web 资源之后还会回到过滤器当中回到过滤器之后如有需求还可以执行放行之后的逻辑放行之后的逻辑我们写在doFilter()这行代码之后。
WebFilter(urlPatterns /*) //配置过滤器要拦截的请求路径 /* 表示拦截浏览器的所有请求
public class DemoFilter implements Filter {Overridepublic void init(FilterConfig filterConfig) throws ServletException {Filter.super.init(filterConfig);System.out.println(init 初始化方法执行了);}Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {System.out.println(Demo 拦截到了请求...放行前逻辑);//放行filterChain.doFilter(servletRequest, servletResponse);System.out.println(DemoFilter放行后逻辑.....);}Overridepublic void destroy() {Filter.super.destroy();}
}过滤器的拦截路径配置 Filter可以根据需求配置不同的拦截资源路径
拦截路径urlPatterns值含义拦截具体路径/login只有访问 /login 路径时才会被拦截目录拦截/emps/*访问/emps下的所有资源都会被拦截拦截所有/*访问所有资源都会被拦截
过滤器链 过滤器链指的是在一个web应用程序当中可以配置多个过滤器多个过滤器就形成了一个过滤器链。 如上图定义了两个过滤器这两个过滤器就形成了一个过滤器链。而这个链上的过滤器在执行的时候会一个一个的执行会先执行第一个Filter放行之后再来执行第二个Filter。要执行到最后一个过滤器放行之后才会访问对应的web资源。如上图先要执行过滤器2放行之后的逻辑再来执行过滤器1放行之后的逻辑最后再给浏览器响应数据。
Filter-登录校验
需求分析
要完成登录校验主要是利用Filter过滤器实现而Filter过滤器的流程步骤
接口文档
请求路径/login
请求方式POST
接口描述该接口用于员工登录Tlias智能学习辅助系统登录完毕后系统下发JWT令牌。请求参数参数格式application/json
请求数据样例{username: jinyong,password: 123456}响应数据参数格式application/json
响应数据样例{code: 1,msg: success,data:eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoi6YeR5bq4IiwiaWQiOjEsInVzZXJuYW1lIjoiamlueW9uZyIsImV4cCI6MTY2MjIwNzA0OH0.KkUc_CXJZJ8Dd063eImx4H9Ojfrr6XMJ-yVzaWCVZCo}请求参数参数说明
响应数据参数说明
思路分析
基于上面业务流程可以分析出具体的操作步骤1. 获取请求url2. 判断请求url中是否包含login如果包含说明是登录操作放行3. 获取请求头中的令牌token4. 判断令牌是否存在如果不存在返回错误结果未登录5. 解析token如果解析失败返回错误结果未登录6. 放行功能开发
登录校验过滤器LoginCheckFilter
Slf4j
WebFilter(urlPatterns /*) //拦截所有请求
public class LoginCheckFilter implements Filter {Overridepublic void doFilter(ServletRequest servletRequest,ServletResponse servletResponse, FilterChain chain) throwsIOException, ServletException {//前置强制转换为http协议的请求对象、响应对象 转换原因要使用子类中特有方法HttpServletRequest request (HttpServletRequest)servletRequest;HttpServletResponse response (HttpServletResponse)servletResponse;//1.获取请求urlString url request.getRequestURL().toString();log.info(请求路径{}, url); //请求路径http://localhost:8080/login//2.判断请求url中是否包含login如果包含说明是登录操作放行if(url.contains(/login)){chain.doFilter(request, response);//放行请求return;//结束当前方法的执行}//3.获取请求头中的令牌tokenString token request.getHeader(token);log.info(从请求头中获取的令牌{},token);//4.判断令牌是否存在如果不存在返回错误结果未登录if(!StringUtils.hasLength(token)){log.info(Token不存在);Result responseResult Result.error(NOT_LOGIN);//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)String json JSONObject.toJSONString(responseResult);response.setContentType(application/json;charsetutf-8);//响应response.getWriter().write(json);return;}//5.解析token如果解析失败返回错误结果未登录try {JwtUtils.parseJWT(token);}catch (Exception e){log.info(令牌解析失败!);Result responseResult Result.error(NOT_LOGIN);//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)String json JSONObject.toJSONString(responseResult);response.setContentType(application/json;charsetutf-8);//响应response.getWriter().write(json);return;}//6.放行chain.doFilter(request, response);}
}在上述过滤器的功能实现中使用到了一个第三方json处理的工具包fastjson。我们要想使用需要引入如下依赖
dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.76/version
/dependency拦截器Interceptor 拦截器是一种动态拦截方法调用的机制类似于过滤器。拦截器是Spring框架中提供的用来动态拦截控制器方法的执行。 拦截器的作用拦截请求在指定方法调用前后根据业务需要执行预先设定的代码。
Interceptor快速入门
拦截器的使用步骤和过滤器类似也分为两步1. 定义拦截器2. 注册配置拦截器自定义拦截器 实现HandlerInterceptor接口并重写其所有方法
//自定义拦截器
Component
public class LoginCheckInterceptor implements HandlerInterceptor {//目标资源方法执行前执行。 返回true放行 返回false不放行Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {System.out.println(preHandle .... );return true; //true表示放行}//目标资源方法执行后执行Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println(postHandle ... );}//视图渲染完毕后执行最后执行Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println(afterCompletion .... );}
}注册配置拦截器 实现WebMvcConfigurer接口并重写addInterceptors方法
Configuration
public class WebConfig implements WebMvcConfigurer {//自定义的拦截器对象Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginCheckInterceptor).addPathPatterns(/** );//设置拦截器拦截的请求路径 /** 表示拦截所有请求}
}Interceptor详解
拦截路径 通过 addPathPatterns(“要拦截路径”) 方法可以指定要拦截的资源还可以调用 excludePathPatterns(“不拦截路径”) 方法指定不拦截的资源。
Configuration
public class WebConfig implements WebMvcConfigurer {//拦截器对象Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginCheckInterceptor).addPathPatterns(/**)//设置拦截器拦截的请求路径 /**表示拦截所有请求.excludePathPatterns(/login);//设置不拦截的请求路径}
}常见拦截路径设置 执行流程 当浏览器发起访问web应用时此时定义的过滤器会拦截到请求。拦截到这次请求之后先执行放行前的逻辑然后再执行放行操作。而由于当前是基于springboot开发的所以放行之后是进入到了spring的环境当中也就是要来访问定义的controller当中的接口方法。 Tomcat并不识别所编写的Controller程序但是它识别Servlet程序所以在Spring的Web环境中提供了一个非常核心的ServletDispatcherServlet前端控制器所有请求都会先进行到DispatcherServlet再将请求转给Controller。 当我们定义了拦截器后会在执行Controller的方法之前请求被拦截器拦截住。执行preHandle() 方法这个方法执行完成后需要返回一个布尔类型的值如果返回true就表示放行本次操作才会继续访问controller中的方法如果返回false则不会放行controller中的方法也不会执行。 在controller当中的方法执行完毕之后再回过来执行 postHandle() 这个方法以及afterCompletion() 方法然后再返回给DispatcherServlet最终再来执行过滤器当中放行后的这一部分逻辑的逻辑。执行完毕之后最终给浏览器响应数据。
过滤器和拦截器的区别
过滤器和拦截器之间的区别主要是两点接口规范不同过滤器需要实现Filter接口而拦截器需要实现HandlerInterceptor接口。拦截范围不同过滤器Filter会拦截所有的资源而Interceptor只会拦截Spring环境中的资源。Interceptor-登录校验 和登录校验Filter过滤器当中的逻辑是完全一致的只需要把原来的过滤器换成拦截器interceptor就可以了。
登录校验拦截器
Slf4j
Component
public class LoginCheckInterceptor implements HandlerInterceptor {//前置方式Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {System.out.println(preHandle .... );//1.获取请求urlString url request.getRequestURL().toString();log.info(请求的ur1:{},url);//2.判断请求url中是否包含login如果包含说明是登录操作放行if (url.contains(login)){log.info(登录操作放行……);return true;}//3.获取请求头中的令牌tokenString token request.getHeader(token);log.info(从请求头中获取的令牌{},token);//4.判断令牌是否存在如果不存在返回错误结果未登录if(!StringUtils.hasLength(token)){log.info(Token不存在);//创建响应结果对象Result responseResult Result.error(NOT_LOGIN);//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)String json JSONObject.toJSONString(responseResult);//设置响应头告知浏览器响应的数据类型为json、响应的数据编码表为utf-8response.setContentType(application/json;charsetutf-8);//响应response.getWriter().write(json);return false;//不放行}//5.解析token如果解析失败返回错误结果未登录try {JwtUtils.parseJWT(token);}catch (Exception e){log.info(令牌解析失败!);//创建响应结果对象Result responseResult Result.error(NOT_LOGIN);//把Result对象转换为JSON格式字符串 (fastjson是阿里巴巴提供的用于实现对象和json的转换工具类)String json JSONObject.toJSONString(responseResult);//设置响应头response.setContentType(application/json;charsetutf-8);//响应response.getWriter().write(json);return false;}//6.放行return true;}
}
注册配置拦截器 Configuration
public class WebConfig implements WebMvcConfigurer {//自定义的拦截器对象Autowiredprivate LoginCheckInterceptor loginCheckInterceptor;Overridepublic void addInterceptors(InterceptorRegistry registry) {//注册自定义拦截器对象registry.addInterceptor(loginCheckInterceptor).addPathPatterns(/**).excludePathPatterns(/login);}
}
异常处理 出现异常之后最终服务端给前端响应回来的数据是一个JSON格式的数据但这种JSON格式的数据不是开发规范中所提到的统一响应结果Result由于返回的数据不符合开发规范所以前端并不能解析出响应的JSON数据。
在三层构架项目中出现了异常该如何处理?方案一在所有Controller的所有方法中进行try…catch处理缺点代码臃肿不推荐方案二全局异常处理器好处简单、优雅推荐全局异常处理器 我们该怎么样定义全局异常处理器定义全局异常处理器非常简单就是定义一个类在类上加上一个注解RestControllerAdvice加上这个注解就代表我们定义了一个全局异常处理器。在全局异常处理器当中需要定义一个方法来捕获异常在这个方法上需要加上注解ExceptionHandler。通过ExceptionHandler注解当中的value属性来指定我们要捕获的是哪一类型的异常。 /*全局异常处理*/
RestControllerAdvice
public class GlobalExceptionHandler {//处理异常ExceptionHandler(Exception.class) //捕获所有异常public Result ex(Exception e){e.printStackTrace();//打印堆栈中的异常信息//捕获到异常之后响应一个标准的Resultreturn Result.error(对不起,操作失败,请联系管理员);}
}