项目实战——实现注册和登录模块
创始人
2024-01-21 07:40:34
0

目录

一、整体框架

二、实现JwtToken验证

 1、添加依赖

2、编写、修改相关类

 三、实现后端 API

 四、实现前端的登录,注册界面



ps:本篇文章篇幅较长,且难度有所提升,希望大家耐心看完,种一棵树最好的时间是十年前,其次是现在

一、整体框架

4.2 实现注册与登录模块

二、实现JwtToken验证

 1、添加依赖

在 pom.xml 中添加下列依赖:

jjwt-api
jjwt-impl
jjwt-jackson

io.jsonwebtokenjjwt-api0.11.2

io.jsonwebtokenjjwt-impl0.11.2runtime

io.jsonwebtokenjjwt-jackson0.11.2runtime

jwt添加依赖

2、编写、修改相关类

实现 JwtUtil 类
在 backend 目录下创建软件包 utils 并创建 JwtUtil 类。
JwtUtil 类为jwt 工具类,用来创建、解析 jwt token

package com.kob.backend.utils;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();}
}

 jwt-utils

 实现 JwtAuthenticationTokenFilter 类
在 backend 的 config 目录下创建 cinfig 软件包,并创建 JwtAuthenticationTokenFilter 类。
实现 JwtAuthenticationTokenFilter 类,用来验证 jwt token ,如果验证成功,则将 User 信息注入上下文中。

package com.kob.backend.config.filter;import com.kob.backend.mapper.UserMapper;
import com.kob.backend.pojo.User;
import com.kob.backend.service.impl.utils.UserDetailsImpl;
import com.kob.backend.utils.JwtUtil;
import com.sun.istack.internal.NotNull;
import io.jsonwebtoken.Claims;
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 {@Autowiredprivate UserMapper userMapper;@Overrideprotected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {String token = request.getHeader("Authorization");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);}
}

在这里插入图片描述

 配置config.SecurityConfig类
放行登录、注册等接口。

package com.kob.backend.config;import com.kob.backend.config.filter.JwtAuthenticationTokenFilter;
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.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 {@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/user/account/token/", "/user/account/register/").permitAll().antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest().authenticated();http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}
}

security-config

 三、实现后端 API

将数据库中的 id 域变为自增。
在 pojo.User 类中添加注解:@TableId(type = IdType.AUTO)
右击 user ,点击 修改表 ,双击 id ,选择 自动增加。同时添加一列 photo,类型设置为 varchar(1000) ,用来存储照片,默认值可以设置为自己的头像。

修改数据库

 修改 User ,添加 photo

package com.kob.backend.pojo;
//与数据库中的表对应
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {@TableId(type = IdType.AUTO)private Integer id;private String username;private String password;private String photo;
}

修改user

 实现接口API
实现API需要三个相关类或接口:

在 service 下创建一个接口。
在 service 下创建一个类实现这个接口。
在 controller 下创建一个类进行操作。

实现 LoginService
验证用户名密码,验证成功后返回 jwt token(令牌)

创建接口:在 service下 创建 user 创建 account 新建一个接口 LoginService

package com.kob.backend.service.user.account;import java.util.Map;public interface LoginService {public Map getToken(String username, String password);}

login接口

 创建实现类:在 service下 impl 下创建 user 创建 account 新建一个实现类LoginServiceImpl

package com.kob.backend.service.impl.user.account;import com.kob.backend.pojo.User;
import com.kob.backend.service.impl.utils.UserDetailsImpl;
import com.kob.backend.service.user.account.LoginService;
import com.kob.backend.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.neo4j.Neo4jProperties;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;@Service
public class LoginServiceImpl implements LoginService {@Autowiredprivate AuthenticationManager authenticationManager;@Overridepublic Map getToken(String username, String password) {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);Authentication authenticate = authenticationManager.authenticate(authenticationToken);UserDetailsImpl loginUser = (UserDetailsImpl) authenticate.getPrincipal();User user = loginUser.getUser();String jwt = JwtUtil.createJWT(user.getId().toString());Map map = new HashMap<>();map.put("error_message", "success");map.put("token", jwt);return map;}
}

login实现类

 创建controller:在 controller 创建 user 创建 account 新建一个LoginController

package com.kob.backend.controller.user.account;import com.kob.backend.service.user.account.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;@RestController
public class LoginController {@Autowiredprivate LoginService loginService;@PostMapping("/user/account/token/")public Map getToken(@RequestParam Map map) {String username = map.get("username");String password = map.get("password");System.out.println(username + ' ' + password);return loginService.getToken(username, password);}
}

在这里插入图片描述

 配置InforService类
根据令牌返回用户信息。

创建接口:在 service下 创建 user 创建 account 新建一个接口 InfoService

package com.kob.backend.service.user.account;import java.util.Map;public interface InfoService {public Map getInfo();
}

在这里插入图片描述

 创建实现类:在 service下 impl 下创建 user 创建 account 新建一个实现类InfoServiceImpl

package com.kob.backend.service.impl.user.account;import com.kob.backend.pojo.User;
import com.kob.backend.service.impl.utils.UserDetailsImpl;
import com.kob.backend.service.user.account.InfoService;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;
@Service
public class InfoServiceImpl implements InfoService {/*** 根据token返回用户信息* @return map存储的信息*/@Overridepublic Map getInfo() {UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();UserDetailsImpl loginUser = (UserDetailsImpl) authentication.getPrincipal();User user = loginUser.getUser();Map map = new HashMap<>();map.put("error_message", "success");map.put("id", user.getId().toString());map.put("username", user.getUsername());map.put("photo", user.getPhoto());return map;}
}

在这里插入图片描述

 创建controller:在 controller 创建 user 创建 account 新建一个InfoController

package com.kob.backend.controller.user.account;import com.kob.backend.service.user.account.InfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;@RestController
public class InfoController {@Autowiredprivate InfoService infoService;@GetMapping("/user/account/info/")public Map getInfo() {return infoService.getInfo();}
}

在这里插入图片描述

 配置RegisterService类
注册账号

创建接口:在 service下 创建 user 创建 account 新建一个接口 RegisterService

package com.kob.backend.service.user.account;import java.util.Map;public interface RegisterService {public Map register(String username, String password, String confirmedPassword);
}

在这里插入图片描述

 创建实现类:在 service下 impl 下创建 user 创建 account 新建一个实现类RegisterServiceImpl

package com.kob.backend.service.impl.user.account;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kob.backend.mapper.UserMapper;
import com.kob.backend.pojo.User;
import com.kob.backend.service.user.account.RegisterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.List;
import java.util.Map;@Service
public class RegisterServiceImpl implements RegisterService {@Autowiredprivate UserMapper userMapper;@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic Map register(String username, String password, String confirmedPassword) {Map map = new HashMap<>();if (username == null) {map.put("error_message", "用户名不能为空");return map;}if (password == null || confirmedPassword == null) {map.put("error_message", "密码不能为空");return map;}//删除首尾的空白字符username = username.trim();if (username.length() == 0) {map.put("error_message", "用户名不能为空");return map;}if (password.length() == 0 || confirmedPassword.length() == 0) {map.put("error_message", "密码不能为空");return map;}if (username.length() > 100) {map.put("error_message", "用户名长度不能大于100");return map;}if (password.length() > 100 || confirmedPassword.length() > 100) {map.put("error_message", "密码不能大于100");return map;}if (!password.equals(confirmedPassword)) {map.put("error_message", "两次输入的密码不一致");return map;}//查询用户名是否重复QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("username", username);List users = userMapper.selectList(queryWrapper);if (!users.isEmpty()) {map.put("error_message", "用户名已存在");return map;}// 添加一个新用户String encodedPassword = passwordEncoder.encode(password);//输入自己的图片地址String photo = "******************************";User user = new User(null, username, encodedPassword, photo);userMapper.insert(user);map.put("error_message", "success");return map;}
}

在这里插入图片描述

 创建controller:在 controller 创建 user 创建 account 新建一个RegisterController

package com.kob.backend.controller.user.account;import com.kob.backend.service.user.account.RegisterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.Map;@RestController
public class RegisterController {@Autowiredprivate RegisterService registerService;@PostMapping("/user/account/register/")public Map register(@RequestParam Map map) {String username = map.get("username");String password = map.get("password");String confirmedPassword = map.get("confirmedPassword");return registerService.register(username, password, confirmedPassword);}
}

在这里插入图片描述

 调试接口API
验证用户登陆:
在 APP.vue 中编写:

注意:这里的Authorization: “Bearer “有空格,且token为自己的浏览器的token,需要更改token。

在这里插入图片描述

 测试成功

 四、实现前端的登录,注册界面

实现两个页面–登陆、注册的前端样式:
从 bootstrap 上去寻找合适的样式:

举个例子:

样式:

Column
Column

在这里插入图片描述

 提交按钮 

创建页面:
在 views 目录下创建 user ,新建两个文件 UserAccountLoginView.vue 和 UserAccountRegisterView.vue 。

实现 UserAccountRegisterView.vue 页面:

在这里插入图片描述

 实现 UserAccountLoginView.vue 页面:

在这里插入图片描述

 在router目录下的index.js中加入路径

修改 index.js:

import UserAccountLoginView from '../views/user/account/UserAccountLoginView'
import UserAccountRegisterView from '../views/user/account/UserAccountRegisterView'const routes = [{path: "/user/account/login",name: "user_account_login",component: UserAccountLoginView,},{path: "/user/account/register",name: "user_account_register",component: UserAccountRegisterView,}]const router = createRouter({history: createWebHistory(),routes
})export default router

在这里插入图片描述

在store下的user.js存储用户信息

在 store 下创建 user.js

import $ from 'jquery'export default {state: {id: "",username: "",password: "",photo: "",token: "",is_login: false,},getters: {},mutations: {updateUser(state, user) {state.id = user.id;state.username = user.username;state.photo = user.photo;state.is_login = user.is_login;},updateToken(state, token) {state.token = token;},},actions: {},modules: {}
}

在这里插入图片描述

 把user加入到全局module
在 store 下的 index.js

import { createStore } from 'vuex'
import ModuleUser from './user'export default createStore({state: {},getters: {},mutations: {},actions: {},modules: {user: ModuleUser,}
})

在这里插入图片描述

 添加辅助函数login
在 store 下的 user.js 修改。

import $ from 'jquery'export default {state: {id: "",username: "",password: "",photo: "",token: "",is_login: false,},getters: {},mutations: {updateUser(state, user) {state.id = user.id;state.username = user.username;state.photo = user.photo;state.is_login = user.is_login;},updateToken(state, token) {state.token = token;},},actions: {login(context, data) {$.ajax({url: "http://127.0.0.1:8080/user/account/token/",type: "post",data: {username: data.username,password: data.password,},success(resp) {if (resp.error_message === "success") {context.commit("updateToken", resp.token);data.success(resp);} else {data.error(resp);}},error(resp) {data.error(resp); }});},},modules: {}
}

在这里插入图片描述

 在 UserAccountLoginView.vue 中实现

在这里插入图片描述

  把内容和变量绑定起来:

{{ error_message }}

在这里插入图片描述

 在登陆界面测试
输入用户名和密码,获取 token。

在这里插入图片描述

 用户名和密码输入正确,点击提交跳到主页面
在 UserAccountLoginView.vue 中实现

在这里插入图片描述

 登陆成功后获取用户的信息
在 user.js 中添加辅助函数

import $ from 'jquery'export default {state: {id: "",username: "",password: "",photo: "",token: "",is_login: false,},getters: {},mutations: {updateUser(state, user) {state.id = user.id;state.username = user.username;state.photo = user.photo;state.is_login = user.is_login;},updateToken(state, token) {state.token = token;},},actions: {login(context, data) {$.ajax({url: "http://127.0.0.1:8080/user/account/token/",type: "post",data: {username: data.username,password: data.password,},success(resp) {if (resp.error_message === "success") {context.commit("updateToken", resp.token);data.success(resp);} else {data.error(resp);}},error(resp) {data.error(resp); }});},getinfo(context, data) {$.ajax({url: "http://127.0.0.1:8080/user/account/info/",type: "get",headers: {Authorization: "Bearer " + context.state.token,},//成功就更新用户。success(resp) {if (resp.error_message === "success") {context.commit("updateUser", {...resp,is_login: true,});data.success(resp);} else {data.error(resp);}},error(resp) {data.error(resp);}});},logout(context) {context.commit("logout");}},modules: {}
}

在这里插入图片描述

 修改 UserAccountLoginView.vue

在这里插入图片描述

 在这里插入图片描述

 把结果返回到右上角个人信息 – 修改导航栏

修改 NavBar.vue:

在这里插入图片描述

 退出登陆
user.js 添加辅助函数:

mutations: {logout(state) {state.id = "";state.username = "";state.photo = "";state.token = "";state.is_login = false;}
},
actions: {logout(context) {context.commit("logout");}
},

在这里插入图片描述

 在 navabar.vue 添加组件:

  • 退出
  • 在这里插入图片描述

     大功告成,记得git 维护~

    相关内容

    热门资讯

    喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
    网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
    发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
    苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...
    为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
    家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
    华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
    四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
    怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
    客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...