【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置Mysql与注册登录模块2

  • 传统的登录验证模式
  • JWT登录验证方式
  • 下载安装依赖
  • 创建JWTUTIL
  • JwtAuthenticationTokenFilter的创建
  • config.SecurityConfig的创建
  • 将用户表格设置成自增ID
  • 在数据库创建新的列
  • 在Pojo.user类中添加注解
  • 实现/user/account/token/
    • 创建LoginService接口
    • 创建RegisterService接口
    • 创建InfoService的接口
    • 实现LoginServiceImpl接口
  • 实现LoginController
  • 实现InfoServiceImpl
  • 实现InfoController
  • 实现RegisterServiceImpl
  • 实现RegisterController
  • 前端页面的实现

传统的登录验证模式

用户在登录之后,数据库会比对用户名和密码,然后如果正确的话返回一个sessionID,服务器端存储SESSIONID,然后 访问其他页面的时候,浏览器会判断session是否有效,然后将用户信息提取到上下文,访问controller层。

JWT登录验证方式

下载安装依赖

  • jjwt-api

  • jjwt-impl

  • jjwt-jackson

添加到pom.xml中

创建JWTUTIL

该类是jwt工具类 用来创建 解析jwt token

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();}
}

JwtAuthenticationTokenFilter的创建

用来验证jwt token 如果验证成功 将USER信息注入上下文当中

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 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 {@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的创建

用来放行登录、注册等接口

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);}
}

将用户表格设置成自增ID

在数据库创建新的列

存储用户头像,数据库存头像 存储的是链接

将自己的用户头像链接复制到数据库表格中

在Pojo.user类中添加注解

设置ID自增

package com.kob.backedn2.pojo;// 数据库一张表对应一个类  @data 将常用的get set方法 添加进去
//@NoArgsConstructor  无参构造函数
//@AllArgsConstructor  有参构造函数
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;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/account/token/

验证用户名密码 验证成功之后 返回jwt token

创建LoginService接口

package com.kob.backedn2.service.user.account;import java.util.Map;public interface LoginService {//     返回登录信息public Map<String,String> login(String username, String password);
}

创建RegisterService接口

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

创建InfoService的接口

package com.kob.backedn2.service.user.account;import java.util.Map;public interface InfoService {public Map<String,String> getInfo();
}

实现LoginServiceImpl接口

package com.kob.backedn2.service.impl.user.account;
import com.kob.backedn2.pojo.User;
import com.kob.backedn2.service.impl.utils.UserDetailsImpl;
import com.kob.backedn2.service.user.account.LoginService;
import com.kob.backedn2.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;// 添加注解service
@Service
public class LoginServiceImpl implements LoginService {// 需要用到的东西 都要注入进来  加上注解 autowired@Autowiredprivate AuthenticationManager authenticationManager;@Overridepublic Map<String, String> login(String username, String password) {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,password);// 登录失败 会自动处理Authentication authenticate = authenticationManager.authenticate(authenticationToken);// 登录成功 获得一个token对象// 取出用户信息UserDetailsImpl loginUser = (UserDetailsImpl) authenticate.getPrincipal();User user = loginUser.getUser();// 获取用户对象// 创建jwt token对象String jwt  = JwtUtil.createJWT(user.getId().toString());Map<String,String> map = new HashMap<>();map.put("error_message","success");map.put("token",jwt);return map;}
}

实现LoginController

该类主要用来根据用户名和密码获取token

package com.kob.backedn2.controller.user.account;
import com.kob.backedn2.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 {//     注入service的接口@Autowiredprivate LoginService loginService;// 登录是post请求  将该链接公开化@PostMapping("/user/account/token/")public Map<String,String> getToken(@RequestParam Map<String,String> map){String username = map.get("username");String password = map.get("password");// 根据用户名和密码 获取tokenreturn loginService.getToken(username,password);}
}

实现InfoServiceImpl

package com.kob.backedn2.service.impl.user.account;
import com.kob.backedn2.pojo.User;
import com.kob.backedn2.service.impl.utils.UserDetailsImpl;
import com.kob.backedn2.service.user.account.InfoService;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
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 {@Overridepublic Map<String, String> getInfo() {UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();UserDetailsImpl loginUser = (UserDetailsImpl) authentication.getPrincipal();User user = loginUser.getUser();Map<String,String> 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;}
}

实现InfoController

package com.kob.backedn2.controller.user.account;import com.kob.backedn2.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<String,String> getinfo(){return infoService.getInfo();}
}

实现RegisterServiceImpl

package com.kob.backedn2.service.impl.user.account;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kob.backedn2.mapper.UserMapper;
import com.kob.backedn2.pojo.User;
import com.kob.backedn2.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<String, String> register(String username, String password, String confirmedPassword) {Map<String,String> 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(username.length() > 100){map.put("error_message","用户名长度不能大于100");return map;}if(password.length() == 0 || confirmedPassword.length() == 0){map.put("error_message","密码长度不能为0");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<User> queryWrapper = new QueryWrapper<User>();queryWrapper.eq("username",username);List<User> users = userMapper.selectList(queryWrapper);if(!users.isEmpty()){map.put("error_message","用户名已经存在");return map;}String encodedPassword = passwordEncoder.encode(password);String photo = "https://cdn.acwing.com/media/user/profile/photo/130933_lg_b73ff6b43b.jpg";User user = new User(null,username,password,photo);userMapper.insert(user);map.put("error_message","success");return map;}
}

实现RegisterController

package com.kob.backedn2.controller.user.account;import com.kob.backedn2.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<String,String>  register(@RequestParam Map<String,String> map){String username = map.get("username");String password = map.get("password");String confirmedPassword = map.get("confirmedPassword");return registerService.register(username,password,confirmedPassword);}
}

前端页面的实现

  • UserAccountLoginView
<template><ContentField><div class="row justify-content-md-center"><div class="col-3"><form @submit.prevent="login"><div class="mb-3"><label for="username" class="form-label">用户名</label><input v-model="username" type="text" class="form-control" id="username" placeholder="请输入用户名"></div><div class="mb-3"><label for="password" class="form-label">密码</label><input v-model="password" type="password" class="form-control" id="password" placeholder="请输入密码"></div><div class="error-message">{{ error_message }}</div><button type="submit" class="btn btn-primary">提交</button></form></div></div></ContentField>
</template><script>
import ContentField from '../../../components/ContentField.vue'
import { useStore } from 'vuex'
import { ref } from 'vue'
import router from '../../../router/index'export default {components: {ContentField},setup() {const store = useStore();let username = ref('');let password = ref('');let error_message = ref('');const login = () => {error_message.value = "";store.dispatch("login", {username: username.value,password: password.value,success() {store.dispatch("getinfo", {success() {router.push({ name: 'home' });console.log(store.state.user);}})},error() {error_message.value = "用户名或密码错误";}})}return {username,password,error_message,login,}}
}
</script><style scoped>
button {width: 100%;
}
div.error-message {color: red;
}
</style>
  • user.js
import $ from 'jquery'export default {state: {id: "",username: "",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;},logout(state) {state.id = "";state.username = "";state.photo = "";state.token = "";state.is_login = false;}},actions: {login(context, data) {$.ajax({url: "http://127.0.0.1:3000/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:3000/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: {}
}

【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置Mysql与注册登录模块2相关推荐

  1. 【Java闭关修炼】SpringBoot项目-贪吃蛇对战小游戏-配置git环境和项目创建

    [Java闭关修炼]SpringBoot项目-贪吃蛇对战小游戏-配置git环境和项目创建 项目的逐步细分 配置git环境 创建项目后端 前后端不分离写法-url访问路径解析资源 安装vue vue文件 ...

  2. 基于Java实现的贪吃蛇大作战小游戏

    贪吃蛇大作战小游戏 整体思路与架构 本项目主要分为三个部分,即UI界面.游戏逻辑与网络传输. UI界面部分,主要是为了实现不同界面之间的切换.包括了注册登陆窗口(loginFrame)与游戏主窗口(G ...

  3. Java实现贪吃蛇大作战小游戏(完整教程+源码)额外实现积分和变速功能

    大家好,我是黄小黄同学!今天给大家带来的是小项目是 基于Java+Swing+IO流实现 的贪吃蛇大作战小游戏.实现了界面可视化.基本的吃食物功能.死亡功能.移动功能.积分功能,并额外实现了主动加速和 ...

  4. 贪吃蛇html网页小游戏,网页贪吃蛇HTML5小游戏制作

    贪吃蛇是以前我们经常在手机里玩的一个小游戏,现在要是把它搬到网页上也会让人更回味.这是一款非常有趣的HTML5响应式网页贪吃蛇小游戏.在游戏中你可以使用键盘的上下左右来控制蛇的运动方向.现在要列出的是 ...

  5. 贪吃蛇宝宝微信小游戏cocoscreator

    非常有趣的创意玩法贪吃蛇一笔画玩法 里面将近有1000关游戏,分为三个难度 乡试 会试 殿试 每个难度通过200关可以解锁下一个难度 在这里插入图片描述 每得到一条蛇就会产生离线收益 兑换道具! 这款 ...

  6. 纯JS实现贪吃蛇——超上瘾小游戏!!!

    效果图 最近使用 JS 写了一个贪吃蛇游戏,效果如下: 谷歌浏览器点击直接在线玩 前言 贪吃蛇作为一款经典又简单的小游戏,每个人都玩过.实现一个贪吃蛇游戏基本具有以下功能: 棋盘(也被称作 " ...

  7. java联机_Java实现简易联网坦克对战小游戏

    介绍 通过本项目能够更直观地理解应用层和运输层网络协议, 以及继承封装多态的运用. 网络部分是本文叙述的重点, 你将看到如何使用Java建立TCP和UDP连接并交换报文, 你还将看到如何自己定义一个简 ...

  8. python小游戏贪吃蛇下载_python小游戏之贪吃蛇

    importpygame,sys,time,randomfrom pygame.locals import * #定义颜色变量 redColour = pygame.Color(255,0,0) bl ...

  9. 贪吃蛇(欢乐小游戏)

    #include"墙.h" #include"标头.h" #include"蛇.h" #include"食物.h" #i ...

最新文章

  1. 哈佛终身教授:年轻人如何做科研?
  2. 淘淘商城学习笔记 之 上传图片到远程服务器,图片的回显出现的bug
  3. 腾讯云首次公开边缘计算网络开源平台,拥抱5G与万物互联
  4. 设python中有模块m、如果希望同时导入m中的所有成员_python-模块
  5. MATLAB gui 对表格增添(删除)数据
  6. epoll边缘触发_epoll事件通知机制详解,水平触发和边沿触发的区别
  7. emq与mysql_EMQ X 插件持久化系列 (五)MySQL MQTT 数据存储
  8. linux fdisk,df,mount挂载及查看磁盘信息
  9. yum 源端软件包扩展
  10. html盒子如何左对齐,【图片】怎么才能让盒子里的LI标签在实现的时候左对齐?在线等急!!!!【web前端开发吧】_百度贴吧...
  11. 2022年python大数据开发学习路线
  12. GAN生成的人脸数据集
  13. RubyOnRails杂记
  14. 电脑版微信定时发送消息
  15. 如何自定义炫酷浏览器主页
  16. 华为服务器查看虚拟ip,裸金属服务器管理虚拟IP地址
  17. ETFE膜和PTFE膜不同之处以及特点-世来福
  18. Python抓取数据具体流程
  19. C语言用指针法输入12个整数,然后按每行4个数输出(刷题)
  20. 微信内置浏览器无法下载app(Android/ios)软件 微信内下载链接打不开的解决方法

热门文章

  1. 基本文件字符流FileWriter、FileReader
  2. 程序员:大师,有些东西我放不下...
  3. Centos下RESTED的使用
  4. 木瓜移动Rap版年终总结, 真的太顶了
  5. pet材料——百度百科
  6. Linux 使用sed指令插入到指定的行的上一行或者下一行
  7. python计算两组数据的协方差_2.6. 协方差估计(Covariance estimation)
  8. 拾光·印记婚纱摄影管理系统的设计与实现mysql
  9. bitnami redmine mysql 密码_Linux使用bitnami安装redmine的图文教程
  10. 第五届中国双创发展大会在杭州落幕 为新经济主体摸索发展路径