个人网站域名取名,辽宁省工程造价网,深圳上位机软件开发培训,备案后网站可以改名吗6.4 关于登录 最简单的登录#xff1a; 1、web登录页填写登录信息#xff0c;前端发送登录信息到后端#xff1b; 2、后端接受登录信息#xff0c;并校验。校验成功#xff0c;返回成功结果。 这种登录会出现一个问题#xff0c;用户1成功登录之后#xff0c;获取到后台…6.4 关于登录 最简单的登录 1、web登录页填写登录信息前端发送登录信息到后端 2、后端接受登录信息并校验。校验成功返回成功结果。 这种登录会出现一个问题用户1成功登录之后获取到后台管理页将这个页面的url分享给用户2用户2没有进行登录就会直接进入到后台管理页容易造成信息泄露 解决方法用户在进入后台管理页之前要进行校验 几种常见的登录验证的方式 方式1、cookie-session 1、用户带登录的时候就会把用户信息发送到后端后端根据用户信息创建一个sessionid将用户登录的相关信息放入到session中后续通过sessionid来进行查找校验并将sessionid传送到前端 2、前端接收到sieeionid之后将其存入到cookie中后续在进行登陆之后会携带cookie后端会根据前端发送过来的cookie解析到其中的sieeionid通过sessionid来查找是否用这个id所对应的用户消息。如果存在用户信息则表示之前这个用户登录过就会放心该用户跳转到其他界面如果该id没有查找到相关的用户信息则表示该用户之前没有进行登录过不会放行 缺点1、cookie只在web网页中生成存在环境限制 2、这种方式不能跨域 3、cookie只能在本机保存不能在集群环境中使用 方式2 token认证 上图的token是存储在redis由于redis是可以部署在集群环境中所以解决了cookie-session的一下缺陷 缺点用户数量大会导致频繁的访问redis校验token对于内存来说有很大的压力。 方式三基于token的jwt令牌认证 1、前端的登录信息发送到后端之后后端基于jwt服务产生一个string类型的字符串成为jwt令牌这个令牌是不需要存储在后端的而是直接返回到前端 2、前端使用本地的存储方式将jwt存储起来后续在进行操作的话会带着jwt令牌到后端后端会对jwt令牌进行校验如果能够正确使用jwt解密说明校验通过了 jwt实际上是一个加解密的过程这个过程是依靠jwt独立的工具包来完成和实现的。 jwt结构是由负载签名和头部组成的由这三部分组成一个串 6.5 jwt令牌工具类的实现 该工具类主要完成jwt的加密和解密操作 首先引入相关的依赖:
新建jwtutil类
public class JWTUtil {private static final Logger logger LoggerFactory.getLogger(JWTUtil.class);/*** 密钥Base64编码的密钥*/private static final String SECRET weS2l8Tp9wDFov9ic72l/9VRT3j9aYfhEfi8qwGMDgU;/*** 生成安全密钥将一个Base64编码的密钥解码并创建一个HMAC SHA密钥。*/private static final SecretKey SECRET_KEY Keys.hmacShaKeyFor(Decoders.BASE64.decode(SECRET));/*** 过期时间(单位: 毫秒)*/private static final long EXPIRATION 60*60*1000*24*30;//一个月/*** 生成密钥** param claim {id: 12, name:张山}* return*/public static String genJwt(MapString, Object claim){//签名算法String jwt Jwts.builder().setClaims(claim) // 自定义内容(载荷).setIssuedAt(new Date()) // 设置签发时间.setExpiration(new Date(System.currentTimeMillis() EXPIRATION)) // 设置过期时间.signWith(SECRET_KEY) // 签名算法和加解密相关.compact();return jwt;}/*** 验证密钥*/
// Claims是jwt里面定义的对象public static Claims parseJWT(String jwt){if (!StringUtils.hasLength(jwt)){return null;}// 创建解析器, 设置签名密钥JwtParserBuilder jwtParserBuilder Jwts.parserBuilder().setSigningKey(SECRET_KEY);Claims claims null;try {//解析tokenclaims jwtParserBuilder.build().parseClaimsJws(jwt).getBody();}catch (ExpiredJwtException e){// 签名验证失败
// logger.error(解析令牌错误,jwt:{}, jwt, e);claims e.getClaims();}return claims;}/*** 从token中获取用户ID*/public static Integer getUserIdFromToken(String jwtToken) {Claims claims JWTUtil.parseJWT(jwtToken);if (claims ! null) {MapString, Object userInfo new HashMap(claims);return (Integer) userInfo.get(userId);}return null;}
} controller层登录接口设计 RequestMapping(/password/login)public CommonResultUserLoginResult userPasswordLogin(Validated RequestBody UserPasswordLoginParam param) {logger.info(userPasswordLogin UserPasswordLoginParam:{},JacksonUtil.writeValueAsString(param));UserLoginDTO userLoginDTO userService.login(param);return CommonResult.success(convertToUserLoginResult(userLoginDTO));} service层登录接口实现 Overridepublic UserLoginDTO login(UserLoginParam param) {UserLoginDTO userLoginDTO;// 类型检查与类型转换java 14及以上版本if (param instanceof UserPasswordLoginParam loginParam) {// 密码登录流程userLoginDTO loginByUserPassword(loginParam);} else if (param instanceof ShortMessageLoginParam loginParam) {// 短信验证码登录流程userLoginDTO loginByShortMessage(loginParam);} else {throw new ServiceException(ServiceErrorCodeConstants.LOGIN_INFO_NOT_EXIST);}return userLoginDTO;}private UserLoginDTO loginByShortMessage(ShortMessageLoginParam loginParam) {if (!RegexUtil.checkMobile(loginParam.getLoginMobile())) {throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);}// 获取用户数据UserDO userDO userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginMobile()));if (userDO null) {throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);} else if (StringUtils.hasText(loginParam.getMandatoryIdentity()) !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);}// 校验验证码String code verificationCodeService.getVerificationCode(loginParam.getLoginMobile());if (!loginParam.getVerificationCode().equals(code)) {throw new ServiceException(ServiceErrorCodeConstants.VERIFICATION_CODE_ERROR);}// 塞入返回值JWTMapString, Object claim new HashMap();claim.put(id, userDO.getId());claim.put(identity, userDO.getIdentity());String token JWTUtil.genJwt(claim);UserLoginDTO userLoginDTO new UserLoginDTO();userLoginDTO.setToken(token);userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));return userLoginDTO;}private UserLoginDTO loginByUserPassword(UserPasswordLoginParam loginParam) {UserDO userDO null;// 判断手机登录还是邮箱登录if (RegexUtil.checkMail(loginParam.getLoginName())) {// 邮箱登录// 根据邮箱查询用户表userDO userMapper.selectByMail(loginParam.getLoginName());} else if (RegexUtil.checkMobile(loginParam.getLoginName())) {// 手机号登录// 根据手机号查询用户表userDO userMapper.selectByPhoneNumber(new Encrypt(loginParam.getLoginName()));} else {throw new ServiceException(ServiceErrorCodeConstants.LOGIN_NOT_EXIST);}// 校验登录信息if (null userDO) {throw new ServiceException(ServiceErrorCodeConstants.USER_INFO_IS_EMPTY);} else if (StringUtils.hasText(loginParam.getMandatoryIdentity()) !loginParam.getMandatoryIdentity().equalsIgnoreCase(userDO.getIdentity())) {// 强制身份登录身份校验不通过throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);} else if (!DigestUtil.sha256Hex(loginParam.getPassword()).equals(userDO.getPassword())) {// 校验密码不同throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);}// 塞入返回值JWTMapString, Object claim new HashMap();claim.put(id, userDO.getId());claim.put(identity, userDO.getIdentity());String token JWTUtil.genJwt(claim);UserLoginDTO userLoginDTO new UserLoginDTO();userLoginDTO.setToken(token);userLoginDTO.setIdentity(UserIdentityEnum.forName(userDO.getIdentity()));return userLoginDTO;}
使用postman对登录进行测试
账号密码 验证码登录 开启redis缓存验证码service redis-server start
发送验证码 验证码登录 6.6 前端登录完善
进行前端测试
密码登录 短信验证码登录 登录成功之后进入新的界面 在登录页面点击注册进入注册见面注册成功之后返回登录界面 6.7 登录拦截器 在设置好jwt令牌登陆之后用户进行登录操作会得到后端传过来的jwt令牌其次用户会拿着这个令牌去访问其他界面的时候后端会对这个jwt令牌进行校验这里采用的是拦截器当然不是所有的请求都需要校验会进行相关配置
登录拦截器
Slf4j
Component
public class LoginInterceptor implements HandlerInterceptor {/**登录拦截器* 预处理业务请求之前调用* param request* param response* param handler* return*/Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 获取请求头,jwt是在request的请求头中的String token request.getHeader(user_token);log.info(获取token{}, token);log.info(获取路径{}, request.getRequestURI());// 令牌解析Claims claims JWTUtil.parseJWT(token);if (claims null) {log.error(解析JWT令牌失败);response.setStatus(401);return false;}log.info(解析JWT令牌成功放行);return true;}
}
配置登录拦截资源
Configuration
public class AppConfig implements WebMvcConfigurer {//配置项Autowiredprivate LoginInterceptor loginInterceptor;private final ListString excludes Arrays.asList(/**/*.html,/css/**,/js/**,/pic/**,/*.jpg,/*.png,/favicon.ico,/**/login,/register,/verification-code/send);Override//添加自定义的登录拦截器public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(loginInterceptor).addPathPatterns(/**).excludePathPatterns(excludes);}
}
ps关于登录的内容就到这里了谢谢观看