花果山博客

news2024/11/26 12:23:28

1:前言
2:项目介绍
3:统一返回结果
4:登录功能实现

前言

简单介绍一个写这个博客的目的。
因为之前学开发都是学完所需的知识点再去做项目,但是这时候在做项目的过程中发现以前学过的全忘了,所以为了减少这种情况,鄙人打算以后通过项目学习技术,说的直接点就是,项目中需要用到哪些技术,那我就去学哪些技术,并用到此项目中。

项目介绍

这是一个SpringBoot + Vue 的分布式前后端项目,具体技术边学边用,因此等此项目完结了,这个项目介绍也就完结了。
目前用到的技术:
数据库:MySql
前端: Vue, Element-ui, LocalStorge
后端:Spring, SpringMvc, Mybatis-Plus, SptingBoot, SpringSecurity

统一返回结果

package com.monkey.monkeybackend.utils.result;


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

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ResultVO {
    private int code;
    private String msg;
    private Object data;
}

package com.monkey.monkeybackend.utils.result;

public class ResultStatus {

    public static final int OK=10000;

    public static final int NO=10001; // 添加购物车失败

}


登录功能我选则的是Jwt_Token实现,将生成的Token存到本地游览器LocalStorge中 下面介绍Token实现的流程

几个实现登录的工具类
先引入依赖

		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.7.5</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.5</version>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.5</version>
            <scope>runtime</scope>
        </dependency>
        

1:检测Token是否过期工具类

package com.monkey.monkeybackend.config.SpringSecurity;

import com.monkey.monkeybackend.Mapper.User.UserMapper;
import com.monkey.monkeybackend.Pojo.user.User;
import io.jsonwebtoken.Claims;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private UserMapper userMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
        // 从哪里读取token
        String token = request.getHeader("Authorization");

        // token以Bearer开头
        if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        token = token.substring(7);

        String userid;
        try {
            Claims claims = JwtUtil.parseJWT(token);
            userid = claims.getSubject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        User user = userMapper.selectById(Integer.parseInt(userid));

        if (user == null) {
            throw new RuntimeException("用户名未登录");
        }

        UserDetailsImpl loginUser = new UserDetailsImpl(user);
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, null);

        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        filterChain.doFilter(request, response);
    }
}

2: 生成Token类

package com.monkey.monkeybackend.config.SpringSecurity;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;

@Component
public class JwtUtil {
    public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14;  // 有效期14天
    public static final String JWT_KEY = "SDFGjhdsfalshdfHFdsjkdsfds121232131afasdfac";

    public static String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
        return builder.compact();
    }

    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey secretKey = generalKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if (ttlMillis == null) {
            ttlMillis = JwtUtil.JWT_TTL;
        }

        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        return Jwts.builder()
                .setId(uuid)
                .setSubject(subject)
                .setIssuer("sg")
                .setIssuedAt(now)
                .signWith(signatureAlgorithm, secretKey)
                .setExpiration(expDate);
    }

    public static SecretKey generalKey() {
        byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
    }

    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(jwt)
                .getBody();
    }
}

3:路径拦截器

package com.monkey.monkeybackend.config.SpringSecurity;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/user/login", "/user/register", "/user/getUserInfoBytoken").permitAll()
                .antMatchers("/blog/article/getArticleContentByLabelId", "/blog/article/pagination",
                        "/blog/article/fireRecently").permitAll()
                .antMatchers("/blog/label/getLabelList").permitAll()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .anyRequest().authenticated();

        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }

}

4:得到用户信息工具类

package com.monkey.monkeybackend.config.SpringSecurity;

import com.monkey.monkeybackend.Pojo.user.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;

/*
 * 通过从数据库中查到的用户名和密码判断该用户是否合格
 * */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDetailsImpl implements UserDetails {

    private User user;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

5:

package com.monkey.monkeybackend.config.SpringSecurity;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.monkey.monkeybackend.Mapper.User.UserMapper;
import com.monkey.monkeybackend.Pojo.user.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username", username);
        User user = userMapper.selectOne(userQueryWrapper);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        return new UserDetailsImpl(user);
    }
}

用户注册实现

// 用户注册
    @Override
    public ResultVO userRegister(Map<String, String> userInfo) {
        String username = userInfo.get("username");
        String password = userInfo.get("password");
        String confirePassword = userInfo.get("confirePassword");

        username = username.trim(); // 删除首位空白字符
        if (username.length() == 0) {
            return new ResultVO(ResultStatus.NO, "用户名不能为空", null);
        }

        if (password == null || password.length() == 0) {
            return new ResultVO(ResultStatus.NO, "密码不能为空", null);
        }

        if (username.length() > 20) {
            return new ResultVO(ResultStatus.NO, "用户名长度不能大于20", null);
        }

        if (password.length() > 20) {
            return new ResultVO(ResultStatus.NO, "密码长度不能大于20", null);
        }

        if (!password.equals(confirePassword)) {
            return new ResultVO(ResultStatus.NO, "两次密码不一致", null);
        }

        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("username", username);
        Long selectCount = userMapper.selectCount(userQueryWrapper);
        if (selectCount > 0) {
            return new ResultVO(ResultStatus.NO, "该用户名已存在,请重新输入", null);
        }

        String encode = passwordEncoder.encode(password);
        String photo = "https://cdn.acwing.com/media/user/profile/photo/246711_md_08990849f1.png";
        User user = new User();
        user.setPassword(encode);
        user.setPhoto(photo);
        user.setUsername(username);
        user.setRegisterTime(new Date());
        int insert = userMapper.insert(user);
        if (insert > 0) {
            return new ResultVO(ResultStatus.OK, "注册成功", null);
        }

        return new ResultVO(ResultStatus.OK, "注册失败", null);
    }

用户登录实现

// 用户登录
    @Override
    public ResultVO userLogin(Map<String, String> userInfo) {
        String username = userInfo.get("username");
        String password = userInfo.get("password");
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = // 将用户名与密码封装成一个加密之后的字符串
                new UsernamePasswordAuthenticationToken(username, password);
        Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken); // 登录失败自动处理

        UserDetailsImpl userDetails = (UserDetailsImpl) authenticate.getPrincipal();
        User user = userDetails.getUser();

        String token = JwtUtil.createJWT(user.getId().toString());

        return new ResultVO(ResultStatus.OK, "登录成功", token);
    }

用户登录前端实现

LoginViews.vue

loginUser() {
            const vue = this;
            store.dispatch("login", {
                username: this.userInformation.username,
                password: this.userInformation.password,
                success() {
                    store.dispatch("getUserInfoBytoken", {
                        success() {   
                            vue.$modal.msgSuccess("登录成功");
                            router.push({
                                name: "home",
                            });
                        },
                        error() {
                            vue.$modal.msgError("登录失败");
                        }
                    })
                },

                error(response) {
                    vue.$modal.msgError(response.msg)
                }
                
            })
        }

store.user.js

login(context, data) {
            $.ajax({
                url: "http://localhost:4000/user/login",
                type: "post",
                data: {
                    username: data.username,
                    password: data.password
                },
                success(response) {
                    if (response.code == "10000") {
                        localStorage.setItem("token", response.data);
                        context.commit("updateToken", response.data);
                        data.success(response);
                    } else {
                        data.error(response);
                    }
                },
                error(response) {
                    data.error(response);
                }
            })
        },

        // 通过token得到用户信息
        getUserInfoBytoken(context, data) {
            $.ajax({
                url: "http://localhost:4000/user/getUserInfoBytoken",
                type: "get",
                headers: {
                    Authorization: "Bearer " + context.state.token,
                },
                success(response) {
                    console.log(response)
                    if (response.code == "10000") {
                        context.commit("updateUserInfo", {
                            ...response.data,
                            is_login: true,
                        });
                        if (data != null) data.success(response)
                    } else {
                        if (data != null) data.error(response);
                    }
                },
                errror(response) {
                    data.error(response);
                }
            })
        },

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/573743.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3导入Element-plus方法

先引入依赖 npm install element-plus --savemain.js中要引入两个依赖 import ElementPlus from element-plus; import "element-plus/dist/index.css";然后 这个东西 我们最好还是挂载vue上 所以 还是 createApp(App).use(ElementPlus)然后 我们可以在组件上试一…

腾讯云轻量服务器镜像安装宝塔Linux面板怎么使用?

腾讯云轻量应用服务器宝塔面板怎么用&#xff1f;轻量应用服务器如何安装宝塔面板&#xff1f;在镜像中选择宝塔Linux面板腾讯云专享版&#xff0c;在轻量服务器防火墙中开启8888端口号&#xff0c;然后远程连接到轻量服务器执行宝塔面板账号密码查询命令&#xff0c;最后登录和…

从零搭建微服务-认证中心(二)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff1a;https://gitee.com/csps/mingyue 文档地址&#xff1a;https://gitee.com/csps/mingyue/wikis 创建新项目 MingYue Idea 创建 maven 项目这…

操作系统第五章——输入输出管理(下)

提示&#xff1a;枕上诗书闲处好&#xff0c;门前风景雨来佳。 文章目录 5.3.1 磁盘的结构知识总览磁盘 磁道 扇区如何从磁盘中读/写数据盘面 柱面磁盘的物理地址磁盘的分类知识回顾 磁盘调度算法知识总览磁盘的读写操作需要的时间先来先服务算法FCFS最短寻找时间优先SSTF扫描算…

SVG图形滤镜

SVG有提供Filter(滤镜)这个东西&#xff0c;可以用来在SVG图形上加入特殊的效果&#xff0c;像是图形模糊化、产生图形阴影、将杂讯加入图形等。以下介绍的是图形模糊化、产生图形阴影这2个滤镜效果。 浏览器对于SVG Filter的支援 SVG : 滤镜 (仅列出部分有使用到的属性) <…

【数据结构】超详细之实现栈

栈的实现步骤 栈的介绍栈的初始化栈的插入(入栈)栈的出栈获取栈顶元素获取栈中有效元素个数检测栈是否为空销毁栈栈元素打印 栈的介绍 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xf…

快捷转换/互转 Markdown 文档和 TypeScript/TypeDoc 注释

背景 作为文档工具人&#xff0c;经常需要把代码里面的注释转换成语义化的 Markdown 文档&#xff0c;有时也需要进行反向操作。以前是写正则表达式全局匹配&#xff0c;时间长了这种方式也变得繁琐乏味。所以写了脚本来互转&#xff0c;增加一些便捷性。 解决方案 注释转 M…

【C++】初遇C++

认识C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要高度的抽象和建模时&#xff0c;C语言则不合适。为了解决软件危机&#xff0c; 20世纪80年代&#xff0c; 计算机界提出了OOP(object orient…

学好网络安全,每年究竟能挣多少钱呢?

薪资的高低&#xff0c;应该是想要转行网络安全的同学最关心的话题了。毕竟薪资是个人水平和自我价值的体现嘛。&#xff08;文末资料&#xff09; 今天就展开谈谈网络安全行业的薪资吧。 先来看张图&#xff0c; 大家在求职时都有一个期望薪资&#xff0c;企业会有一个实际薪…

5月的面试难度有点大....

大家好&#xff0c;最近有不少小伙伴在后台留言&#xff0c;又得准备面试了&#xff0c;不知道从何下手&#xff01; 不论是跳槽涨薪&#xff0c;还是学习提升&#xff01;先给自己定一个小目标&#xff0c;然后再朝着目标去努力就完事儿了&#xff01; 为了帮大家节约时间&a…

R语言实践——使用rWCVP映射多样性

使用rWCVP映射多样性 加载库工作流1. 物种丰富度2. 特有物种丰富度3. 特定区域的物种热力图 加载库 library(rWCVP) library(tidyverse) library(sf) library(gt)工作流 1. 物种丰富度 我们可以使用 wcvp_summary 将所有物种的全球出现数据压缩为每个 WGSRPD 3 级区域的原始…

chatgpt赋能python:Python三角函数角度的介绍

Python三角函数角度的介绍 Python语言为各种计算提供了强大的支持。而Python在数学领域的支持更是非常强大&#xff0c;包括对三角函数角度的计算。在Python中&#xff0c;支持常用的三角函数&#xff0c;例如sin、cos、tan等。这些函数都需要将角度转换为弧度&#xff0c;并且…

车载网络测试 - CANCANFD - 基础篇_01

目录 问题思考&#xff1a; 一、为什么需要总线? 二、什么是CAN总线? 三、为什么是CAN总线? 四、曾经的车用总线 1、SAEJ1850(Class2) 2、SAEJ1708 3、K-Line 4、BEAN 5、 byteflight, K-Bus 6、D2B 五、当前的车用总线 1、CAN 2、LIN 3、FlexRay 4、MOST 六…

C#中的DataGridView中添加按钮并操作数据

背景&#xff1a;最近在项目中有需求需要在DataGridView中添加“删除”、“修改”按钮&#xff0c;用来对数据的操作以及显示。 在DataGridView中显示需要的按钮 首先在DataGridView中添加需要的列&#xff0c;此列是用来存放按钮的。 然后在代码中“画”按钮。 if (e.Column…

你知道什么叫三目表达式吗

目录 什么是三目表达式&#xff1f; 运用 1.单个使用 2.嵌套使用 什么是三目表达式&#xff1f; 1.三目表达式是一种编程中常见的表达式,它能够有效地帮助我们解决一些问题。 2.三目表达式由三个部分组成,分别是:条件表达式、结果表达式 听不懂么&#xff0c;那我们就来举个…

网页制作-技术学习笔记

PxCook PxCook测量像素工具下载 https://www.fancynode.com.cn/pxcookPxCook基本操作 通过软件打开设计图 打开软件 创建web项目 拖拽入设计图&#xff0c;png用设计模式 psd用开发模式 常用快捷键 放大设计图&#xff1a;ctrl 缩小设计图&#xff1a;ctrl - - 移动…

一、STM32开发环境的搭建(Keil+CubeMX)

1、STM32开发环境所需的东西 (1)KeilMDK安装包。 (2)STM32CubeMX。 (3)Keil软件对应的单片机pack包。 (4)STM32Cube MCU包。 2、Keil简介及安装 略 3、CubeMX简介及安装 3.1、CubeMX简介 (1)STM32CubeMX是一种图形工具&#xff0c;通过分步过程可以非常轻松地配置STM3…

Flutter 可冻结的侧滑表格 sticky-headers-table 结合 NestedScrollView 吸顶悬浮的使用实践

最近在做flutter web的开发&#xff0c;需要做一个类似云文档中表格固定顶部栏和左侧栏的需求&#xff0c;也就是冻结列表的功能 那么在pub上呢也有不少的开源库&#xff0c;比如&#xff1a; table_sticky_headers data_table_2 如果说只是简单的表格和吸顶&#xff0c;那么这…

cf1750E Bracket Cost

前言&#xff1a; 好久没训练了,来做道计数题找找感觉。**期末毁我青春 大意&#xff1a; 定义对于一个括号串 s的值&#xff0c;为通过最小次数以下操作使 s 实现括号匹配的操作次数。 选择一个子串&#xff0c;循环右移一位。在任意一个位置插入一个任意括号。 求一个括…

【Python 变量和数据类型】零基础也能轻松掌握的学习路线与参考资料

一、Python 变量 Python 变量是数据储存的地方&#xff0c;使用变量可以在程序中持续存储数据&#xff0c;Python 中的变量可以储存任何类型的数据&#xff0c;如文本、数字、列表、元组、字典等。下面是 Python 变量学习路线&#xff1a; 1. 了解 Python 变量 Python 变量是…