欢迎光临
我们一直在努力

Tlias智能学习辅助系统(黑马)--day06

目标:完成登录认证

1.如何完成登录认证?

需求:用户输入用户名和密码,然后去数据库中查询该用户名和密码是否正确,正确则登录成功,并返回给前端用户的id,usename,name,token(此处先不用管,下面会详细介绍),否则登录失败

分析:1.创建LoginInfo实体类 存储id,usename,name,token等信息

            2.用户名和密码封装在emp中即可

            3.三层架构

             controller 接收请求参数 调用service层(返回的信息为null则不正确,反之则正确)响应数据

             service   调用mapper层

             mapper 根据用户名和密码查询信息

             4.因为访问路径改变,所以我们新建一个LoginController类,service,mapper沿用Emp开头的就可以

具体代码实现

Emp实现类

package com.qlu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
private Integer id; //ID,主键
private String username; //用户名
private String password; //密码
private String name; //姓名
private Integer gender; //性别, 1:男, 2:女
private String phone; //手机号
private Integer job; //职位, 1:班主任,2:讲师,3:学工主管,4:教研主管,5:咨询师
private Integer salary; //薪资
private String image; //头像
private LocalDate entryDate; //入职日期
private Integer deptId; //关联的部门ID
private LocalDateTime createTime; //创建时间
private LocalDateTime updateTime; //修改时间

//封装部门名称数
private String deptName; //部门名称
//封装工作经历
private List<EmpExpr> exprList;
}

LoginInfo实现类

package com.qlu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginInfo {
private Integer id;
private String usename;
private String name;
private String token;
}

controller

package com.qlu.controller;

import com.qlu.pojo.Emp;
import com.qlu.pojo.LoginInfo;
import com.qlu.pojo.Result;
import com.qlu.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
@RequestMapping("/login")
public class LoginController {
@Autowired
private EmpService empService;
@PostMapping
public Result login(@RequestBody Emp emp){
log.info("接受用户名和密码:{}",emp);
LoginInfo loginInfo = empService.login(emp);
if(loginInfo==null){
return Result.error("用户名或者密码错误");
}
return Result.success(loginInfo);
}
}

service实现类中的方法重写

@Override
public LoginInfo login(Emp emp) {
Emp loginEmp = empMapper.login(emp);
if(loginEmp!=null){
return new LoginInfo(emp.getId(), emp.getUsername(), emp.getName(), null);
}
return null;
}

mapper

Emp login(Emp emp);

配置文件

<!–定义Mapper映射文件的约束和基本结构–>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qlu.mapper.EmpMapper">
<delete id="deleteById">
delete from emp where id in
<foreach collection="ids" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
<select id="page" resultType="com.qlu.pojo.Emp">
select e.*, d.name deptName from emp e left join dept d on e.dept_id = d.id
<where>
<if test="name!=null and name!=''">
e.name like concat('%',#{name},'%')
</if>
<if test="gender!=null">
and e.gender=#{gender}
</if>
<if test="begin!=null and end!=null">
and e.entry_date between #{begin} and #{end}
</if>
</where>
order by e.update_time desc
</select>
<select id="login" resultType="com.qlu.pojo.Emp">
select * from emp e where e.username=#{username} and e.password=#{password};
</select>
</mapper>

2.jwt令牌技术优化登录认证

我们发现在登录界面直接访问登陆后的界面,依然可以对其操作,那么我们如何进行优化呢?在这里引入jwt令牌技术,这相当于我们的访问权限凭证

当我们点击登录按钮时,服务端会给我们查询用户名和密码是否正确,如果正确,创建一个令牌并自动相应给浏览器,浏览器段在发送请求到服务端时会自动将令牌传给服务端,服务端检验到令牌的时候便会允许我们操作。这就是令牌技术

令牌技术实现:

1.引入jwt令牌技术依赖

<!– JWT依赖–>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

2.在util包下引入jwt工具类

package com.qlu.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="SVRIRUlNQQ==";
private static Long expire = 43200000L;
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;
}
public static Claims parseJWT(String jwt){
Claims claims = Jwts.parser().setSigningKey(signKey).parseClaimsJwt(jwt).getBody();
return claims;
}
}

3.service层优化

@Override
public LoginInfo login(Emp emp) {
Emp loginEmp =empMapper.login(emp);
if(loginEmp!=null){
HashMap<String, Object> dataMap = new HashMap<>();
dataMap.put("id",loginEmp.getId());
dataMap.put("username",loginEmp.getUsername());
String jwt = JwtUtils.generateJwt(dataMap);
return new LoginInfo(loginEmp.getId(), loginEmp.getUsername(), loginEmp.getName(), jwt);
}
return null;
}

3.fiter过滤器进一步优化

我们发现即使加入了令牌技术,用户依旧可以在退出登录的情形下访问并操作我们的管理系统,原因是为什么呢?

我们从底层进行分析:用户点击登录时,浏览器会向服务器发送请求,服务器通过用户名和密码查询信息,如果数据库中存在该用户名和密码,则登录成功,为其下发一个令牌,并在响应数据时自动响应给前端,浏览器自动存储令牌,并在下一次发送请求时将令牌自动发送给服务器,因为企业一般需要有多台服务器,多个功能模块,所以为了方便,在浏览器与服务器中间加入了过滤器,自动拦截服务器发送到请求,并具有使服务器负载均衡的功用,在过滤器中进行令牌校验,校验成功则允许使用相应功能,反之弹出登陆界面让你进行登录。

那么有人问?我的第一次登录请求为什么没有拦截呢?

这里就要引入过滤器,他将我们的登录请求自动过滤到服务器,以方便后续功能的实现。所谓过滤,就是过滤掉登录请求和令牌校验成功的请求。

那么我们如何实现一个过滤器呢?

1.定义一个类 实现filter接口并重写三个方法

2.Filter类上加入@WebFilter注解配置拦截路径。在引导类上加入@ServletComponentScan注解提供Servlet组件支持

代码实现

package com.qlu.filter;

import com.qlu.utils.JwtUtils;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.logging.LogRecord;

@Slf4j
@WebFilter(urlPatterns = "/*")
public class TokenFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String url = request.getRequestURI().toString();
if(url.contains("login")){
log.info("登录成功,直接放行");
filterChain.doFilter(request,response);
return;
}
String jwt = request.getHeader("token");
if(!StringUtils.hasLength(jwt)){
log.info("获取到的jwt令牌为空,返回错误结果");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
try {
JwtUtils.parseJWT(jwt);
} catch (Exception e) {
e.printStackTrace();
log.info("解析令牌失败,返回错误结果");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return;
}
log.info("令牌合法,放行");
filterChain.doFilter(request,response);
}
}

不要忘记启动类上加入@ServletComponentScan

4.关于拦截器与过滤器的区别

过滤器是servlet组件中的东西,所以拦截范围更大,能拦截项目中的所有请求

而拦截器是spring中的东西,所以拦截范围较小,只能拦截spring中的请求

两者使用哪一种都可以,如果两者同时存在,那么先经过过滤器再经过拦截器。

赞(0)
未经允许不得转载:171主机测评 » Tlias智能学习辅助系统(黑马)--day06
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址