springBoot web项目的登录注册

# ecologicalhome项目的登录注册

基于SpringBoot框架实现的web登录注册项目,

使用框架或技术:

后端 SpringBoot、mybatis、mysql、shiro 等

前端 jquery Thymeleaf 基于jQ的Ajax等

1. 效果图演示

1. 登录:

1. 主页登录注册入口

![主页登录,注册入口](vx_images/388972113238996.png)

2. 点击登录来到登录页面![登录页面](vx_images/186772413226863.png)

3. 登录页面实现ajax查询用户名是否存在,js用户名,密码格式限制,点击验证码实现刷新对登录按钮进行限制,只有用户名,密码符合要求才可以点击登录,shiro实现登录控制,记住我,点击免费注册跳转注册页

用户名控制![用户名控制](vx_images/581433213247029.png)

密码控制![密码控制](vx_images/285183313239698.png)

ajax验证用户名 失去光标执行验证![用户名验证实现异步刷新](vx_images/76563513236253.png)

点击刷新验证码 验证码局部刷新![刷新前](vx_images/503383813232007.png)![刷新后](vx_images/63533913249887.png)

2. 注册:

1. 主页点击注册,或者登录页点击免费注册![注册页](vx_images/471845213247491.png)

2. 注册页Ajax实现判断注册邮箱是否被使用,js对密码的控制,验证确认密码是否一致,输入都符合要求时解除对注册按钮的控制,ajax发送邮箱验证码

邮箱控制![邮箱控制](vx_images/206230014244993.png)

密码控制![密码控制](vx_images/58600114226234.png)

再次输入密码控制![再次输入密码控制](vx_images/554000114248674.png)

点击发送邮箱验证码![aaa](vx_images/186030615237356.png)![验证码](vx_images/368050615230490.png)

2. 登录部分核心代码

1. 目录结构:

![目录结构](vx_images/517100915221020.png)

2. index.html

```

<p class="fl" th:if="${loginUser==null}">

<a th:href="@{/toLogin}" id="login">登录</a>

<a th:href="@{/toRegister}" id="reg">注册</a>

</p>

<p class="fl" th:if="${loginUser!=null}">

<a th:href="@{/logout}" id="logout">注销</a>

</p>

```

3. loginController

```

/**

* 去登录页面

* @return 登陆页面

*/

@RequestMapping("/toLogin")

public String toLogin(){

return "member/login";

}

```

4. 准备图片验证码工具类

工具类网上有众多优秀的资源

本篇博客验证码获取工具类来源于:

https://blog.csdn.net/rickiyeat/article/details/55050440

ValidateCode

```

package com.cheng.utils;

import java.util.Random;

import java.awt.image.BufferedImage;

import java.awt.Graphics;

import java.awt.Font;

import java.awt.Color;

/**

* 验证码生成器类,可生成数字、大写、小写字母及三者混合类型的验证码。 支持自定义验证码字符数量; 支持自定义验证码图片的大小; 支持自定义需排除的特殊字符;

* 支持自定义干扰线的数量; 支持自定义验证码图文颜色

*/

public class ValidateCode {

/**

* 验证码类型为仅数字 0~9

*/

public static final int TYPE_NUM_ONLY = 0;

/**

* 验证码类型为仅字母,即大写、小写字母混合

*/

public static final int TYPE_LETTER_ONLY = 1;

/**

* 验证码类型为数字、大写字母、小写字母混合

*/

public static final int TYPE_ALL_MIXED = 2;

/**

* 验证码类型为数字、大写字母混合

*/

public static final int TYPE_NUM_UPPER = 3;

/**

* 验证码类型为数字、小写字母混合

*/

public static final int TYPE_NUM_LOWER = 4;

/**

* 验证码类型为仅大写字母

*/

public static final int TYPE_UPPER_ONLY = 5;

/**

* 验证码类型为仅小写字母

*/

public static final int TYPE_LOWER_ONLY = 6;

private ValidateCode() {

}

/**

* 生成验证码字符串

*

* @param type

* 验证码类型,参见本类的静态属性

* @param length

* 验证码长度,大于0的整数

* @param exChars

* 需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null)

* @return 验证码字符串

*/

public static String generateTextCode(int type, int length, String exChars) {

if (length <= 0)

return "";

StringBuffer code = new StringBuffer();

int i = 0;

Random r = new Random();

switch (type) {

// 仅数字

case TYPE_NUM_ONLY:

while (i < length) {

int t = r.nextInt(10);

if (exChars == null || exChars.indexOf(t + "") < 0) {// 排除特殊字符

code.append(t);

i++;

}

}

break;

// 仅字母(即大写字母、小写字母混合)

case TYPE_LETTER_ONLY:

while (i < length) {

int t = r.nextInt(123);

if ((t >= 97 || (t >= 65 && t <= 90)) && (exChars == null || exChars.indexOf((char) t) < 0)) {

code.append((char) t);

i++;

}

}

break;

// 数字、大写字母、小写字母混合

case TYPE_ALL_MIXED:

while (i < length) {

int t = r.nextInt(123);

if ((t >= 97 || (t >= 65 && t <= 90) || (t >= 48 && t <= 57))

&& (exChars == null || exChars.indexOf((char) t) < 0)) {

code.append((char) t);

i++;

}

}

break;

// 数字、大写字母混合

case TYPE_NUM_UPPER:

while (i < length) {

int t = r.nextInt(91);

if ((t >= 65 || (t >= 48 && t <= 57)) && (exChars == null || exChars.indexOf((char) t) < 0)) {

code.append((char) t);

i++;

}

}

break;

// 数字、小写字母混合

case TYPE_NUM_LOWER:

while (i < length) {

int t = r.nextInt(123);

if ((t >= 97 || (t >= 48 && t <= 57)) && (exChars == null || exChars.indexOf((char) t) < 0)) {

code.append((char) t);

i++;

}

}

break;

// 仅大写字母

case TYPE_UPPER_ONLY:

while (i < length) {

int t = r.nextInt(91);

if ((t >= 65) && (exChars == null || exChars.indexOf((char) t) < 0)) {

code.append((char) t);

i++;

}

}

break;

// 仅小写字母

case TYPE_LOWER_ONLY:

while (i < length) {

int t = r.nextInt(123);

if ((t >= 97) && (exChars == null || exChars.indexOf((char) t) < 0)) {

code.append((char) t);

i++;

}

}

break;

}

return code.toString();

}

/**

* 已有验证码,生成验证码图片

*

* @param textCode

* 文本验证码

* @param width

* 图片宽度

* @param height

* 图片高度

* @param interLine

* 图片中干扰线的条数

* @param randomLocation

* 每个字符的高低位置是否随机

* @param backColor

* 图片颜色,若为null,则采用随机颜色

* @param foreColor

* 字体颜色,若为null,则采用随机颜色

* @param lineColor

* 干扰线颜色,若为null,则采用随机颜色

* @return 图片缓存对象

*/

public static BufferedImage generateImageCode(String textCode, int width, int height, int interLine,

boolean randomLocation, Color backColor, Color foreColor, Color lineColor) {

BufferedImage bim = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

Graphics g = bim.getGraphics();

// 画背景图

g.setColor(backColor == null ? getRandomColor() : backColor);

g.fillRect(0, 0, width, height);

// 画干扰线

Random r = new Random();

if (interLine > 0) {

int x = 0, y = 0, x1 = width, y1 = 0;

for (int i = 0; i < interLine; i++) {

g.setColor(lineColor == null ? getRandomColor() : lineColor);

y = r.nextInt(height);

y1 = r.nextInt(height);

g.drawLine(x, y, x1, y1);

}

}

// 写验证码

// g.setColor(getRandomColor());

// g.setColor(isSimpleColor?Color.BLACK:Color.WHITE);

// 字体大小为图片高度的80%

int fsize = (int) (height * 0.8);

int fx = height - fsize;

int fy = fsize;

g.setFont(new Font("Default", Font.PLAIN, fsize));

// 写验证码字符

for (int i = 0; i < textCode.length(); i++) {

fy = randomLocation ? (int) ((Math.random() * 0.3 + 0.6) * height) : fy;// 每个字符高低是否随机

g.setColor(foreColor == null ? getRandomColor() : foreColor);

g.drawString(textCode.charAt(i) + "", fx, fy);

fx += fsize * 0.9;

}

g.dispose();

return bim;

}

/**

* 生成图片验证码

*

* @param type

* 验证码类型,参见本类的静态属性

* @param length

* 验证码字符长度,大于0的整数

* @param exChars

* 需排除的特殊字符

* @param width

* 图片宽度

* @param height

* 图片高度

* @param interLine

* 图片中干扰线的条数

* @param randomLocation

* 每个字符的高低位置是否随机

* @param backColor

* 图片颜色,若为null,则采用随机颜色

* @param foreColor

* 字体颜色,若为null,则采用随机颜色

* @param lineColor

* 干扰线颜色,若为null,则采用随机颜色

* @return 图片缓存对象

*/

public static BufferedImage generateImageCode(int type, int length, String exChars, int width, int height,

int interLine, boolean randomLocation, Color backColor, Color foreColor, Color lineColor) {

String textCode = generateTextCode(type, length, exChars);

BufferedImage bim = generateImageCode(textCode, width, height, interLine, randomLocation, backColor, foreColor,

lineColor);

return bim;

}

/**

* 产生随机颜色

*

* @return

*/

private static Color getRandomColor() {

Random r = new Random();

Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));

return c;

}

}

```

5. LoginController

```

/**

* 生成验证码图片

* * 验证码类型为仅数字 0~9 0

* * 验证码类型为仅字母,即大写、小写字母混合1

* * 验证码类型为数字、大写字母、小写字母混合2

* * 验证码类型为数字、大写字母混合3

* * 验证码类型为数字、小写字母混合4

* * 验证码类型为仅大写字母5

* * 验证码类型为仅小写字母6

* @param response 传递生成数据

* @throws IOException 抛出io异常

*/

@RequestMapping("/validateCode")

public void validateCode(HttpServletResponse response) throws IOException {

String code = ValidateCode.generateTextCode(4, 4, null);

System.out.println("生成的验证码"+code);

Subject subject = SecurityUtils.getSubject();

Session session = subject.getSession();

session.removeAttribute("validateCode");

session.setAttribute("validateCode",code);

BufferedImage bufferedImage = ValidateCode.generateImageCode(code, 120, 40, 7, true, null, null, null);

ImageIO.write(bufferedImage, "JPEG", response.getOutputStream());

}

```

6. login.html

提前准备jquery,和jquery.cookie两个js文件

jquery-3.6.0.js

jquery.cookie.js

```

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

<meta charset="UTF-8">

<title>登录</title>

<link rel="stylesheet" type="text/css" th:href="@{member/css/public.css}"/>

<link rel="stylesheet" type="text/css" th:href="@{member/css/login.css}"/>

<script type="text/javascript" th:src="@{member/js/jquery-3.6.0.js}"></script>

<script type="text/javascript" th:src="@{js/jquery.cookie.js}"></script>

<script type="text/javascript" th:src="@{member/js/login.js}"></script>

</head>

<body>

<!-------------------login-------------------------->

<div class="login">

<form th:action="@{/login}" method="post" οnsubmit="return checkForm()">

<h1><a th:href="@{/index}"><img th:src="@{member/img/temp/logo.png}" alt=""></a></h1>

<div class="msg-warn hide"><b>公共场所切勿自动登录,以防账号丢失</b></div>

<label>

<input type="text" name="userName" id="userName" placeholder="昵称/邮箱/手机号:" required="" οnkeyup="checkUserName2()"/>

<!-- autofocus="" 自动聚焦光标-->

</label>

<label>

<input type="password" name="password" id="password" placeholder="密码:" required="" οnkeyup="checkPassword()"/>

</label>

<div>

<label>

<input style="width: 100px;" type="text" name="verificationCode" placeholder="验证码:" required="" />

</label>

<a href="javascript:changeVerificationCode()" rel="external nofollow" >

<div style="margin-right: 87px; margin-top: 10px;float: right"><img id="verificationCode" th:src="@{/validateCode}" alt=""></div>

</a>

</div>

<p style="color:#ff0000; font-size: 17px;" th:text="${msg}" id="msg" th:if="${not #strings.isEmpty(msg)}" ></p>

<p style="font-size: 17px;" id="info"></p>

<!-- <div>-->

<div class="checkboxRememberAndLogin">

<label>

<input type="hidden" name="rememberMe" value="0">

<input style="width: 17px;height: 17px;" type="checkbox" name="rememberMe" id="rememberMe" value="1"/>

</label>&nbsp;记住我

</div>

<p><input type="submit" name="" value="登 录" ></p>

<p class="txt"><a class="" th:href="@{/toRegister}">免费注册</a><a href="forget.html">忘记密码</a></p>

</form>

</div>

</body>

</html>

```

7. login.js

```

var usernameObj;

var passwordObj;

var emailObj;

var againPasswordObj;

var usernameMsg;

var passwordMsg;

var emailMsg;

var againPasswordMsg;

// 页面加载之后, 获取页面中的对象

window.onload = function() {

usernameObj = document.getElementById("userName");

passwordObj = document.getElementById("password");

emailObj = document.getElementById("email");

againPasswordObj = document.getElementById("againPassword");

usernameMsg = document.getElementById("info");

passwordMsg = document.getElementById("info");

emailMsg = document.getElementById("info")

againPasswordMsg = document.getElementById("info");

};

//login的表单验证

function checkForm() { // 验证整个表单

var bUsername = checkUserName2();

var bPassword = checkPassword();

return bUsername && bPassword; // return false后, 事件将被取消

}

// register的表单验证

function checkFormRegister() { // 验证整个表单

var bCheckEmail = checkEmail();

var bPassword = checkPassword();

var bAgainPassword = checkAgainPassword()

return bCheckEmail && bPassword &&bAgainPassword; // return false后, 事件将被取消

}

//验证邮箱

function checkEmail() { // 验证邮箱

var regex = /^[\w-]+@([\w-]+\.)+[a-zA-Z]{2,4}$/;

var value =emailObj.value;

var msg = "";

if (!value)

msg = "邮箱必须填写:";

else if (!regex.test(value))

msg = "邮箱格式不合法:";

emailMsg.innerHTML = msg;

emailObj.style.color = msg === "" ? "black" : "red";

emailMsg.style.color = msg === "" ? "black" : "red";

return msg === "";

}

function checkUsername() { // 验证用户名

var regex = /^[a-zA-Z_]\w{0,9}$/; // 字母数字下划线1到10位, 不能是数字开头

var value = usernameObj.value;// 获取usernameObj中的文本

var msg = ""; // 最后的提示消息, 默认为空

if (!value) // 如果用户名没填, 填了就是一个字符串可以当作true, 没填的话不论null或者""都是false

msg = "用户名必须填写:"; // 改变提示消息

else if (!regex.test(value)) // 如果用户名不能匹配正则表达式规则

msg = "用户名不合法:"; // 改变提示消息

usernameMsg.innerHTML = msg; // 将提示消息放入SPAN

usernameObj.parentNode.parentNode.style.color = msg === "" ? "black" : "red"; // 根据消息结果改变tr的颜色

return msg === ""; // 如果提示消息为空则代表没出错, 返回true

}

//Login验证用户名/邮箱/手机号的输入是否合理

function checkUserName2() { // 验证输入是否为昵称,邮箱,电话

var regexName = /^[\u4e00-\u9fa5a-zA-Z0-9]{2,8}$/; //^[\u4e00-\u9fa5a-zA-Z0-9]{6,12}$汉字,字母,数字

var regexEmail = /^[\w-]+@([\w-]+\.)+[a-zA-Z]{2,4}$/;

var regexPhone = /^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/ //手机号/^(13[0-9]|14[5|7]|15[0-9]|18[0-9]|17[0-9])d{8}$/;

var value = usernameObj.value;// 获取usernameObj中的文本

var flag = 0

var msg = ""; // 最后的提示消息, 默认为空

// if (!value) // 如果用户名没填, 填了就是一个字符串可以当作true, 没填的话不论null或者""都是false

// msg = "昵称/邮箱/电话,必须填写:"; // 改变提示消息

if(regexName.test(value)){

msg = "用户名格式正确"; //"用户名为2-8个字符"

flag = 1;

}

else if (regexEmail.test(value)){

// 如果邮箱能匹配正则表达式规则

msg ="邮箱格式正确"; // 改变提示消息 "邮箱格式为X@X.X"

flag = 1;

}

else if (regexPhone.test(value)){

msg = "电话格式正确";

flag = 1;

//"电话不符合要求\n以13[0-9],14[579],15[0-3,5-9],16[6],\n17[0135678],18[0-9],19[89]开头11位的电话号码"

}

else {

msg = "用户名为2-8个字符 邮箱格式为X@X.X 电话格式13[0-9],14[579],15[0-3,5-9],16[6],17[0135678],18[0-9],19[89]开头11位数字"

flag = 0;

}

usernameMsg.innerHTML = msg; // 将提示消息放入SPAN

usernameObj.style.color = flag === 1 ? "green" : "red"; // 根据消息结果改变tr的颜色parentNode获取父类,childNodes获取子类标签

usernameMsg.style.color = flag === 1 ? "green" : "red";

return flag !== 0; // 如果提示消息为空则代表没出错, 返回true

}

// 验证密码

function checkPassword() {

var regex = /^[^\u4e00-\u9fa5 ]{6,16}$/;//不含中文空格

// 任意字符, 6到16位/^.{6,16}$/ 字母特殊字符数字/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[~@#$%*-+=:,\\?\[\]{}]).{6,16}$/

var value = passwordObj.value;

var msg = "";

if (!value)

msg = "密码必须填写:";

else if (!regex.test(value))

msg = "密码为6-16位任意字符";

passwordMsg.innerHTML = msg;

passwordMsg.style.color = msg === "" ? "green" : "red";

return msg === "";

}

// 验证确认密码

function checkAgainPassword() {

var regex = /^[^\u4e00-\u9fa5 ]{6,16}$/;//不含中文空格

var passwordValue = passwordObj.value;

var againPassword = againPasswordObj.value;

var msg = "";

if(!againPassword){

msg = "确认密码必须填写";

}

else if (!regex.test(passwordValue))

msg = "密码为6-16位任意字符";

else if (passwordValue !== againPassword){

msg = "密码必须保持一致";

}

againPasswordMsg.innerHTML = msg;

againPasswordMsg.style.color = msg === "" ? "black" : "red";

againPasswordObj.style.color = msg === "" ? "black" : "red";

return msg === "";

}

//判断用户名是否正确,(验证存在ajax)

function checkUser() {

var name = $("#userName").val();

$.ajax({

type : "post",

url : "/userNameAjax?userName="+name,

data : name,

// dataType:"String",

success : function(data) {

// var node = document.getElementById("info");

// node.firstChild.nodeValue = data;

document.getElementById("info").innerHTML = data;

document.getElementById("info").style.color= "red";

}

,

error:function(data){

alert("连接失败");

}

});

}

$(document).ready(function() {

$("#userName").blur(function() {

checkUser();

});

})

//判断注册邮箱是否被使用,(ajax)

function checkRegEmail() {

var email = $("#email").val();

$.ajax({

type : "post",

url : "/emailAjax?email="+email,

data : email,

success : function(data) {

document.getElementById("info").innerHTML = data;

document.getElementById("info").style.color= "red";

}

,

error:function(data){

alert("连接失败");

}

});

}

$(document).ready(function() {

$("#email").blur(function() {

checkRegEmail();

});

})

//点击刷新验证码图片

function changeVerificationCode() {

document.getElementById("verificationCode").src="/validateCode?flag="+Math.random();

}

//点击发送邮箱验证码

function changeEmailCode() {

var email = $("#email").val();

var msg = "";

if (!email)

msg = "请先填写邮箱!";

else{

$.ajax({

type : "post",

url : "/emailCode?email="+email,

data : email,

success : function(data) {

document.getElementById("info").innerHTML = data;

document.getElementById("info").style.color= "green";

}

,

error:function(data){

document.getElementById("info").innerHTML = "发送失败,请重试或检查网络状态";

document.getElementById("info").style.color= "red";

}

});

}

// $("verificationCode").attr('src',"/validateCode?flag="+Math.random());

// document.getElementById("emailCodeTime").src="/emailCode?email="+email;

// window.location.href="/emailCode?email="+email;

emailMsg.innerHTML = msg;

emailMsg.style.color = msg === "" ? "black" : "red";

}

//计时器

$(function() {

var emailCodeTime = $("#emailCodeTime");

var countdown = 60;//倒计时总时间,为了演示效果,设为5秒,一般都是60s

$(function() {

emailCodeTime.click(setTime);

})

$("#changeEmailCode").click(function() {

changeEmailCode();

})

function setTime() {

if (countdown === 0) {

emailCodeTime.attr("disabled", false);

emailCodeTime.html("获取验证码");

emailCodeTime.removeClass("disabled");

countdown = 60;

return;

} else {

emailCodeTime.addClass("disabled");

emailCodeTime.attr("disabled", true);

emailCodeTime.html("重新发送(" + countdown + ")");

countdown--;

}

setTimeout(setTime, 1000);

}

})

```

8. ajax所需要的方法判断用户名&判断邮箱

LoginController

```

/**

* userNameAjax 登录时后使用ajax验证用户名,邮箱,电话是否存在

* @param userName 接收用户名,邮箱,电话参数

* @return 返回反馈信息

*/

@RequestMapping("/userNameAjax")

@ResponseBody

public String userNameAjax(@RequestParam("userName")String userName ){

User user=loginService.validateLoginUserName(userName);

if(user==null){

user= loginService.validateLoginEmail(userName);

if(user==null){

user=loginService.validateLoginTelephone(userName);

}

}

System.out.println("user---->"+user);

System.out.println(userName);

if(user==null){

return "输入的昵称/邮箱/电话,不存在";

}

return null;

}

```

9. 点击登录,执行登录方法login

```

@PostMapping("/login")

public String login(@RequestParam("userName") String userName,

@RequestParam("password") String password,

@RequestParam("verificationCode") String verificationCode,

@RequestParam("rememberMe") String rememberMe,

ModelMap modelMap){

Subject subject = SecurityUtils.getSubject();

UsernamePasswordToken token = new UsernamePasswordToken(userName, password);

if(verificationCode==null){

modelMap.addAttribute("msg","验证码为空!");

return "member/login";

}

if(rememberMe.equals("1")) {

token.setRememberMe(true);

}

Session session = subject.getSession();

String validateCode =(String) session.getAttribute("validateCode");

// System.out.println("获取session的验证码"+validateCode);

// System.out.println("登录填写的验证码"+verificationCode);

if(!verificationCode.equals(validateCode)){

modelMap.addAttribute("msg","验证码错误!");

return "member/login";

}

try {

subject.login(token);//执行登录的方法

return "redirect:/index";

} catch (UnknownAccountException e) {

modelMap.addAttribute("msg","账号错误!");

return "member/login";

} catch (IncorrectCredentialsException e) {

modelMap.addAttribute("msg", "密码错误!");

return "member/login";

}

}

```

10. LoginServiceImpl实现类方法

```

@Service

public class LoginServiceImpl implements LoginService {

@Autowired

LoginMapper loginMapper;

@Override

public User validateLogin1(String loginValue, String password) {

return loginMapper.validateLogin1(loginValue,password);

}

@Override

public User validateLoginUserName(String loginValue) {

return loginMapper.validateLoginUserName(loginValue);

}

@Override

public User validateLoginEmail(String loginValue) {

return loginMapper.validateLoginEmail(loginValue);

}

@Override

public User validateLoginTelephone(String loginValue) {

return loginMapper.validateLoginTelephone(loginValue);

}

}

```

11. LoginMapper中的方法定义

```

@Mapper

public interface LoginMapper {

User validateLogin1(@Param("VI") String loginValue,@Param("password")String password);

User validateLoginUserName(@Param("VI") String loginValue);//验证信息verificationInformation

User validateLoginEmail(@Param("VI") String loginValue);

User validateLoginTelephone(@Param("VI") String loginValue);

}

```

12. LoginMapper.xml

```

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper

PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.cheng.member.mapper.LoginMapper">

<select id="validateLogin1" resultType="User" parameterType="String">

select * from ecologicalhome.user where userName=#{VI} and password=#{password};

</select>

<select id="validateLoginUserName" resultType="User" parameterType="String">

select * from ecologicalhome.user

where userName=#{VI};

</select>

<select id="validateLoginEmail" resultType="User" parameterType="String">

select * from ecologicalhome.user

where email=#{VI};

</select>

<select id="validateLoginTelephone" resultType="User" parameterType="String">

select * from ecologicalhome.user

where telephone=#{VI};

</select>

</mapper>

```

13. 登录中的Shiro登录认证

```

@Configuration

public class ShiroConfig {

//ShiroFilterFactoryBean 3.

@Bean(name = "shiroFilterFactoryBean")

public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){

ShiroFilterFactoryBean bean =new ShiroFilterFactoryBean();

//设置安全管理器

bean.setSecurityManager(defaultWebSecurityManager);

Map<String,String> filterMap = new LinkedHashMap<>();

// 授权

filterMap.put("/user/addUser","perms[user:addUser]");

filterMap.put("/user/updateUser","perms[user:updateUser]");

filterMap.put("/user/*","authc");

bean.setFilterChainDefinitionMap(filterMap);

//设置登录的请求

bean.setLoginUrl("/toLogin");

//未授权的请求

bean.setUnauthorizedUrl("/noauth");

return bean;

}

@Bean

public SimpleCookie rememberMeCookie(){

// 这个参数是 cookie 的名称,叫什么都行,我这块取名 rememberMe

SimpleCookie simpleCookie = new SimpleCookie("rememberMe");

// setcookie 的 httponly 属性如果设为 true 的话,会增加对 xss 防护的安全系数,

// 只能通过http访问,javascript无法访问,防止xss读取cookie

simpleCookie.setHttpOnly(true);

simpleCookie.setPath("/");

// 记住我 cookie 生效时间30天 ,单位是秒

simpleCookie.setMaxAge(7*24*60*60);

return simpleCookie;

}

/**

* cookie管理对象;记住我功能,rememberMe管理器

* @return

*/

@Bean

public CookieRememberMeManager rememberMeManager(){

CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();

cookieRememberMeManager.setCookie(rememberMeCookie());

//rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)

cookieRememberMeManager.setCipherKey(Base64.decode("4AvVhmFLUs0KTA3Kprsdag=="));

return cookieRememberMeManager;

}

/**

* FormAuthenticationFilter 过滤器 过滤记住我

* @return

*/

@Bean

public FormAuthenticationFilter formAuthenticationFilter(){

FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();

// 对应 rememberMeCookie() 方法中的 name

formAuthenticationFilter.setRememberMeParam("rememberMe");

return formAuthenticationFilter;

}

//DefaultWebSecurityManager 2.

@Bean(name = "defaultWebSecurityManager")

public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){

DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

// 需要关联UserRealm

securityManager.setRealm(userRealm);

securityManager.setRememberMeManager(rememberMeManager());

// 将 sessionManager 注入到 SecurityManager 中,否则不会生效

// securityManager.setSessionManager(sessionManager());

return securityManager;

}

//创建realm 对象 自定义对象 1.

@Bean(name = "userRealm")

public UserRealm userRealm(){

return new UserRealm();

}

//整合ShiroDialect :用来整合shiro和thymeleaf

@Bean

public ShiroDialect getShiroDialect(){

return new ShiroDialect();

}

}

```

14. aa

```

//自定义的UserRealm extends

public class UserRealm extends AuthorizingRealm {

User user;

@Autowired

LoginService loginService;

//授权

@Override

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

System.out.println("执行啦 --------->>授权doGetAuthorizationInfo");

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

// info.addStringPermission("user:index");

Subject subject = SecurityUtils.getSubject();

User currentUser = (User) subject.getPrincipal();

// 设置当前用户的权限

// info.addStringPermission(currentUser.getPower());

return info;

}

// 认证 authentication

@Override

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

System.out.println("执行啦 --------->>认证doGetAuthorizationInfo");

//用户名,密码

//链接真实的数据库

Subject subject = SecurityUtils.getSubject();

UsernamePasswordToken userToken = (UsernamePasswordToken) token;

user=loginService.validateLoginUserName(userToken.getUsername());

if(user==null){

user= loginService.validateLoginEmail(userToken.getUsername());

if(user==null){

user=loginService.validateLoginTelephone(userToken.getUsername());

if(user==null){

user=loginService.validateLoginTelephone(userToken.getUsername());

}

}

}

if(user==null){//没有这个人

return null;//会抛出一个异常

}

else {

if(String.valueOf(userToken.getPassword()).equals(user.getPassword())){

Session session = subject.getSession();

session.setAttribute("loginUser",user);

}

}

// System.out.println(user);

// System.out.println("simpleAuthenticationInfo-----------"+simpleAuthenticationInfo);

//密码认证 shiro帮我们做

return new SimpleAuthenticationInfo(user, user.getPassword(), "");

}

}

```

3. 注册部分核心代码

1. registerController

```

/**

* toRegister 去注册页面

* @return

*/

@RequestMapping("/toRegister")

public String toRegister(){

return "member/reg";

}

```

2. register.thml

```

<head>

<meta charset="UTF-8">

<title>注册</title>

<link rel="stylesheet" type="text/css" th:href="@{member/css/public.css}"/>

<link rel="stylesheet" type="text/css" th:href="@{member/css/login.css}"/>

<script type="text/javascript" th:src="@{member/js/jquery-3.6.0.js}"></script>

<script type="text/javascript" th:src="@{member/js/login.js}"></script>

</head>

<body>

<!-------------------reg-------------------------->

<div class="reg">

<form th:action="@{/register}" method="post" οnsubmit="return checkFormRegister()">

<h1><a th:href="@{/index}"><img th:src="@{member/img/temp/logo.png}"></a></h1>

<p><label>

<input type="email" name="email" id="email" placeholder="请输入邮箱:" required="" οnkeyup="checkEmail()">

</label></p>

<p><label>

<input type="password" name="password" id="password" placeholder="请输入密码:" οnkeyup="checkPassword()">

</label></p>

<p><label>

<input type="password" id="againPassword" placeholder="请确认密码:" οnkeyup="checkAgainPassword()">

</label></p>

<p class="txtL txt">

<div>

<label>

<input style="width: 100px;" type="text" name="emailCode" placeholder="验证码:" required="" />

</label>

<a id="changeEmailCode">

<button type="button" class="emailCode" id="emailCodeTime">获取验证码</button>

</a>

</div>

</p>

<p style="font-size: 17px;" id="info"></p>

<p style="color:#ff0000;font-size: 17px;" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}" ></p>

<p><input type="submit" name="" value="注册"></p>

<p class="txtL txt">注册即同意该&nbsp;&nbsp;&nbsp;<a href="#">使用条款和隐私策略</a></p>

<p class="txt"><a th:href="@{/toLogin}"><span></span>已有账号登录</a></p>

<a th:href="@{/}" class="off"><img th:src="@{member/img/temp/off.png}"></a>

</form>

</div>

</body>

```

3. login.js文件在登录页面已经展示,现在展示部分核心代码

```

//点击发送邮箱验证码

function changeEmailCode() {

var email = $("#email").val();

var msg = "";

if (!email)

msg = "请先填写邮箱!";

else{

$.ajax({

type : "post",

url : "/emailCode?email="+email,

data : email,

success : function(data) {

document.getElementById("info").innerHTML = data;

document.getElementById("info").style.color= "green";

}

,

error:function(data){

document.getElementById("info").innerHTML = "发送失败,请重试或检查网络状态";

document.getElementById("info").style.color= "red";

}

});

}

// $("verificationCode").attr('src',"/validateCode?flag="+Math.random());

// document.getElementById("emailCodeTime").src="/emailCode?email="+email;

// window.location.href="/emailCode?email="+email;

emailMsg.innerHTML = msg;

emailMsg.style.color = msg === "" ? "black" : "red";

}

//计时器

$(function() {

var emailCodeTime = $("#emailCodeTime");

var countdown = 60;//倒计时总时间,为了演示效果,设为5秒,一般都是60s

$(function() {

emailCodeTime.click(setTime);

})

$("#changeEmailCode").click(function() {

changeEmailCode();

})

function setTime() {

if (countdown === 0) {

emailCodeTime.attr("disabled", false);

emailCodeTime.html("获取验证码");

emailCodeTime.removeClass("disabled");

countdown = 60;

return;

} else {

emailCodeTime.addClass("disabled");

emailCodeTime.attr("disabled", true);

emailCodeTime.html("重新发送(" + countdown + ")");

countdown--;

}

setTimeout(setTime, 1000);

}

})

```

4. ajax执行发送验证码的方法

在这之前需要引入email的相关jar包

```

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail -->

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-mail</artifactId>

<version>2.6.4</version>

</dependency>

```

application.yml相关配置

```

spring:

mail:

host: smtp.qq.com

username: 264xxxx933@qq.com

password: ncslrxtbvrigebad

properties:

mail:

stmp:

ssl:

enable: true

```

RegisterCotroller

```

/**

* register 执行注册方法,判断验证是否正确

* @param user 用户对象

* @param emailCode 邮箱验证码

* @param modelMap 向前端反馈信息

* @return 注册成功重定向到去登录页,失败返回到注册页

*/

@PostMapping("/register")

public String register(User user,@RequestParam("emailCode")String emailCode, ModelMap modelMap){

Subject subject = SecurityUtils.getSubject();

Session session = subject.getSession();

String validateCode =(String) session.getAttribute("validateCode");

String emailName =(String) session.getAttribute("emailName");

if(validateCode!=null&&emailName.equals(user.getEmail()) && validateCode.equals(emailCode)){

do {

user.setUserName("用户" + outputString.getNumberString(5));

} while (loginService.validateLoginUserName(user.getUserName()) != null);

user.setCountry("中国");

user.setIntroduce("");

user.setRole("member");

user.setUserAvatar("member/img/userAvatar/default_avatar.png");

user.setRegisterTime(new Timestamp(new Date().getTime()));

int reg=registerService.insertUser(user);

if(reg>0){

return "redirect:/toLogin";

}

else {

modelMap.addAttribute("msg","注册失败!");

return "member/reg";

}

}else {

modelMap.addAttribute("msg","验证码错误!");

return "member/reg";

}

}

/**

* emailAjax 利用ajax判断邮箱是否已经被注册

* @param email 接收邮箱号

* @return 返回判断信息,未被使用返回空

*/

@RequestMapping("/emailAjax")

@ResponseBody

public String emailAjax(@RequestParam("email") String email){

User user= loginService.validateLoginEmail(email);

if(user!=null){

System.out.println("这个邮箱被使用:"+email);

return "邮箱已被使用,请登录";

}

return null;

}

// 获取配置中的邮件发送方

@Value("${spring.mail.username}")

private String from;

/**

* 实现页面不刷新,发送邮箱验证码

* @param email 指定验证码发送到的邮箱

* @return 返回是否发送成功验证码,不成功返回null

*/

@RequestMapping("/emailCode")

@ResponseBody

public String emailCode(@RequestParam("email") String email) {

User user = loginService.validateLoginEmail(email);

System.out.println("emailCode------>user:"+user);

if(user==null){

String code = ValidateCode.generateTextCode(0, 6, null);

System.out.println("注册邮箱生成的验证码"+code+"----"+new Timestamp(new Date().getTime()));

Subject subject = SecurityUtils.getSubject();

Session session = subject.getSession();

session.removeAttribute("validateCode");

session.setAttribute("validateCode",code);

session.removeAttribute("emailName");

session.setAttribute("emailName",email);

SimpleMailMessage message = new SimpleMailMessage();

message.setSubject("智能家居");

message.setText("你获取的智能家居验证码为:"+code+" 验证码请在3分钟内使用,切勿向任何人泄露验证码");

message.setTo(email);

message.setFrom(from);

mailSender.send(message);

return "验证码已发送";

}

return null;

}

```

5. RegisterService和RegisterMapper类中只有一个插入数据方法不在描述

### 总结:

#### 第一次写博客,多多包涵

### 祝大家学有所成,快快上岸

### 关注我不迷路

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个流行的Java框架,它简化了构建生产级应用程序的过程,特别是对于那些基于Web的应用。在Spring Boot中实现登录和注册功能,通常会用到Spring Security模块,这是一个强大的安全框架,可以帮助处理身份验证和授权。 以下是Spring Boot项目中实现登录注册的基本步骤: 1. **设置依赖**: 首先,在`pom.xml`或`build.gradle`文件中添加Spring Security的依赖。 2. **配置Spring Security**: 在`application.properties`或`application.yml`中配置Spring Security的基本属性,如HTTP端点保护、密码编码规则等。 3. **创建用户模型**(User Model): 定义一个User实体类,包含用户名、密码和其他必要的字段(如邮箱、角色等)。 4. **注册/登录控制器**(Controller): 使用Spring Security的`@RestController`和`@PostMapping`创建API接口,接收用户提交的注册和登录求。 5. **视重定向**: 创建HTML模板用于显示登录/注册表单,并配置视解析器,以便在用户成功登录或注册后跳转到相应的页面。 6. **实现认证逻辑**: 实现`UserDetailsService`接口来加载用户数据,以及`PasswordEncoder`接口来处理密码加密。 7. **表单验证**: 使用`@Valid`注解和`@NotBlank`等验证注解来确保输入数据的正确性。 8. **错误处理**: 设置异常处理器来处理未授权访问或其他错误情况。 9. **配置Thymeleaf或FreeMarker等模板引擎**: 显示登录失败消息或者成功提示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值