#项目架构、功能点

架构:

  • Springboot2.5.+
  • MySQL数据库8.0+(记录用户信息、角色清单、用户角色对照表)
  • 持久层Mybatis
  • 用户注册页面RegisterPage采用Thymeleaf动态网页
  • 登录页面Login采用SpringSecurity标准表单登录网页

功能点:

  • 实现用户自助注册登录
  • 实现用户自助选择角色
  • 用户信息、角色清单、用户角色对照表采用SpringSecurity标准架构
  • 用户密码采用SpringSecurity首推的BCryptPasswordEncoder加密算法记录
  • 实现登陆后URL访问与角色对应

#用户自助注册及登录流程图

#项目文件结构、数据库设计、Maven依赖、aplication配置

文件结构:

数据库设计:

user表,记录用户信息

role表,记录角色清单

user_role表,用户角色对照表

Maven依赖:

        <!--Spring Security--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><!--Mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--Thymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>

因为使用Mybatis,所以build要添加XML资源目录,否则编译会缺少UserMapper.XML。

        <resources><resource><!-- XML默认是放在resource下面,如果有自定义,需要把resource加上 --><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory></resource></resources>

aplication配置:

#datasource mybatis配置--------------------------------
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/jpa?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=12345678
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#datasource mybatis配置--------------------------------
#thymeleaf配置--------------------------------
spring.thymeleaf.cache=true
spring.thymeleaf.checktemplate=true
spring.thymeleaf.check-template-location=true
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.suffix=.html
spring.thymeleaf.prefix=classpath:/templates/
#Thymeleaf配置--------------------------------

#用户前端注册页面registerPage.html代码(Thymeleaf模板动态网页)

这里通过用户注册接口registerController去数据库查询角色清单(role表),将查询结果写入roles集合中,通过Thymeleaf模板进行调用并加入select-option选择列表,供用户注册时选择某一角色。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>新用户注册</title>
</head>
<body><h2 align="center">新用户注册</h2><hr width="40%" color="gray"/><form action="/doregister" method="post" enctype="application/x-www-form-urlencoded"><table width="40%" bgcolor="gray" align="center"><tr><td align="right">用户名:</td><td><input type="text" name="username" size="25px" maxlength="10" placeholder="请输入用户名最长10位" required/></td></tr><tr><td align="right">密码:</td><td><input type="password" name="password" size="25px" maxlength="20" placeholder="请输入密码最长20位" required></td></tr><tr><td align="right">角色:</td><td><label><select name="role"><option>--请选择角色--</option><option th:each="role:${roles}"th:value="${role.id}"th:text="${role.nameZH}"th:selected="${role==role.id}"></option></select></label></td></tr><tr><td align="right"><input type="submit" value="提交注册"></td><td></td></tr></table></form>
</body>
</html>

#实体类、Mybatis持久层接口、用户服务类、用户注册及登录接口

角色实体类Role:

package com.example.springsecurity.Entity;
import java.io.Serializable;
public class Role implements Serializable {private Integer id;private String name;private String nameZH;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getNameZH() {return nameZH;}public void setNameZH(String nameZH) {this.nameZH = nameZH;}
}

用户实体类User(包含所具有的角色) :

该实体类主要用于用户登录,需要使用标准的UserDetails接口。

package com.example.springsecurity.Entity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class User implements UserDetails {private Integer id;private String username;private String password;private Boolean enabled;private Boolean locked;private List<Role> roles;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities(){List<SimpleGrantedAuthority> authorities= new ArrayList<>();for (Role r:roles){authorities.add(new SimpleGrantedAuthority(r.getName()));}return authorities;}@Overridepublic String getPassword(){return password;}@Overridepublic String getUsername(){return username;}@Overridepublic boolean isAccountNonExpired(){return true;}@Overridepublic boolean isAccountNonLocked(){return true;}@Overridepublic boolean isCredentialsNonExpired(){return true;}@Overridepublic boolean isEnabled(){return true;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public void setUsername(String username) {this.username = username;}public void setPassword(String password) {this.password = password;}public Boolean getEnabled() {return enabled;}public void setEnabled(Boolean enabled) {this.enabled = enabled;}public Boolean getLocked() {return locked;}public void setLocked(Boolean locked) {this.locked = locked;}public List<Role> getRoles() {return roles;}public void setRoles(List<Role> roles) {this.roles = roles;}
}

用户注册实体类UserRegister(包含用户需要申请的角色) :

该实体类主要用于用户注册。

package com.example.springsecurity.Entity;
public class UserRegister {private Integer id;private String username;private String password;private Boolean enabled;private Boolean locked;private Integer role;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Boolean getEnabled() {return enabled;}public void setEnabled(Boolean enabled) {this.enabled = enabled;}public Boolean getLocked() {return locked;}public void setLocked(Boolean locked) {this.locked = locked;}public Integer getRole() {return role;}public void setRole(Integer role) {this.role = role;}
}

Mybatis持久层接口:

主要包含UserMapper.xml和UserMapper interface,包含:

loadUserByUsername方法,通过用户名查询用户

getUserRolesByUid方法,通过用户ID获取用户所有角色

addUserByUsername方法,通过UserRegister实体类注册新用户

getAllRole方法,获取当前系统所有角色

addRole方法,通过用户ID和角色ID,给用户添加角色

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.springsecurity.Repository.UserMapper"><select id="loadUserByUsername" resultType="com.example.springsecurity.Entity.User">select * from user where username=#{username}</select><select id="getUserRolesByUid" resultType="com.example.springsecurity.Entity.Role">select * from role r,user_role ur where r.id=ur.rid and ur.uid=#{id}</select><insert id="addUserByUsername" parameterType="com.example.springsecurity.Entity.UserRegister">insert into user(username,password,enabled,locked) values(#{username},#{password},#{enabled},#{locked})</insert><select id="getAllRole" resultType="com.example.springsecurity.Entity.Role">select * from role</select><insert id="addRole">insert into user_role(uid,rid) values(#{uid},#{rid})</insert>
</mapper>
package com.example.springsecurity.Repository;
import com.example.springsecurity.Entity.Role;
import com.example.springsecurity.Entity.User;
import com.example.springsecurity.Entity.UserRegister;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserMapper {User loadUserByUsername(String username);List<Role> getUserRolesByUid(Integer id);int addUserByUsername(UserRegister userRegister);List<Role> getAllRole();int addRole(Integer uid,Integer rid);
}

用户服务类UserService:

是上述接口方法的实现类,包含:

loadUserByUsername实现方法,用于查询用户以及所具有的角色

addUserByUsername实现方法,用于实现用户注册以及角色注册

getAllRole实现方法,用户查询所有角色清单

package com.example.springsecurity.Service;
import com.example.springsecurity.Entity.Role;
import com.example.springsecurity.Entity.User;
import com.example.springsecurity.Entity.UserRegister;
import com.example.springsecurity.Repository.UserMapper;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService implements UserDetailsService {@AutowiredUserMapper userMapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{User user = userMapper.loadUserByUsername(username);if(user == null){throw new UsernameNotFoundException("账户不存在!");}user.setRoles(userMapper.getUserRolesByUid(user.getId()));return user;}public String addUserByUsername(UserRegister userRegister){User newuser = userMapper.loadUserByUsername(userRegister.getUsername());if (newuser != null){return "账户存在,注册失败!";}else {//新用户密码采用BCryptPasswordEncoder(10)格式存入数据库userRegister.setPassword(new BCryptPasswordEncoder(10).encode(userRegister.getPassword()));//设置用户状态可用,没有锁定userRegister.setEnabled(true);userRegister.setLocked(false);//执行用户注册int adduser = userMapper.addUserByUsername(userRegister);//用户成功注册后,添加用户角色if(adduser > 0){User getuser =userMapper.loadUserByUsername(userRegister.getUsername());int addrole = userMapper.addRole(getuser.getId(),userRegister.getRole());if (addrole > 0){return "账户注册成功,角色注册成功!";}else{return "账户注册成功!角色注册失败!";}}else {return "账户注册失败!";}}}public List<Role> getAllRole(){return userMapper.getAllRole();}
}

登录接口:

登录接口包含:

registerController用户注册接口

doRegisterController执行用户注册接口及返回注册结果

HelloController登录接口

package com.example.springsecurity.Controller;
import com.example.springsecurity.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class registerController {@AutowiredUserService userService;@GetMapping("/register")//registerController用户注册接口,将所有角色信息数据库取值并绑定roles赋给前端registerPage.htmlpublic ModelAndView resgister(){ModelAndView mv = new ModelAndView();mv.addObject("roles",userService.getAllRole());mv.setViewName("registerPage");return mv;}
}
package com.example.springsecurity.Controller;
import com.example.springsecurity.Entity.UserRegister;
import com.example.springsecurity.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class doRegisterController {@AutowiredUserService userService;@PostMapping("/doregister")//doRegisterController执行用户注册接口及返回注册结果public String doregister(UserRegister userRegister){return userService.addUserByUsername(userRegister);}
}
package com.example.springsecurity.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
//HelloController登录接口,URL访问权限控制,分别对应不同的角色方能访问
public class HelloController {@GetMapping("/admin/hello")public String admin(){return "hello admin";}@GetMapping("/user/hello")public String user(){return "hello user";}@GetMapping("/db/hello")public String dba(){return "hello dba";}@GetMapping("/hello")public String hello(){return "hello";}
}

#Spring Security核心配置类WebSecurityLoginConfig

①注入用户服务类用于登录验证。

②配置用户登录密码需要BCryptPasswordEncoder(10)密文认证。

③对可访问资源URL限定固定的角色方能访问。

④用户注册接口和执行用户注册接口允许访问。

⑤成功登陆后跳转hello接口。

package com.example.springsecurity.Config;
import com.example.springsecurity.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Configuration
public class WebSecurityLoginConfig extends WebSecurityConfigurerAdapter {//注入用户服务@AutowiredUserService userService;//配置用户登录密码需要BCryptPasswordEncoder密文认证@BeanPasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder(10);}//基于数据库的用户账号密码、角色、过期、锁定等认证@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception{auth.userDetailsService(userService);}@Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception {httpSecurity.authorizeRequests()//对可访问URL资源进行角色控制.antMatchers("/admin/**").hasRole("admin").antMatchers("/user/**").access("hasAnyRole('admin','user')").antMatchers("/db/**").access("hasRole('dba') and hasRole('admin')")//用户注册接口和执行用户注册接口允许访问.antMatchers("/register","/doregister").permitAll()//用户访问其他URL资源都必须认证后访问,即登陆后访问.anyRequest().authenticated()//开启表单登录,即登录界面,登录URL为/login,登录参数用户名username密码password//Ajax或移动端通过POST请求登录,接口为/login,permitAll表示登录不需要认证即可访问.and().formLogin().loginProcessingUrl("/login").permitAll()//成功登录后跳转到hello页面.successHandler(new AuthenticationSuccessHandler() {@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {response.setContentType("application/json;charset=utf-8");response.sendRedirect("/hello");}}).and().csrf().disable();}
}

#启动数据库和项目,开始验证测试

第一步测试注册:

输入用户注册接口http://localhost:8080/register,自动跳转到registerPage.html,并将所有角色信息从数据库取出赋值给前端。

提交注册,跳转到http://localhost:8080/doregister接口,返回注册结果。

数据库中user表已经新增ceshi用户。

用户角色表user_role中新增数据:ceshi用户(uid:15)对应用户角色(rid:3)。

第二步测试登录:

我们输入登录网址http://localhost:8080/login或者任意输入后缀地址,均可以访问登录接口。

用ceshi用户登陆后,具有用户角色,可以访问/user/hello接口或者hello接口,当然系统会自动跳转到hello接口页面。

当我们访问管理员接口/admin/hello接口,系统会因为缺少权限而拒绝访问Forbidden。

#总结

SpringSecurity可以非常轻松的实现用户登录验证、注册、跳转、URL接口访问控制等。

Thymeleaf可以将后端数据赋值给前端,便于前端使用,非常适合做登录网页前端设计。

Mybatis持久层非常灵活,可以实现用户自助注册、角色赋值、用户查询、角色查询等各种方法并于数据库交互,实现存储加密。

通过以上技术,我们就可以轻松打造简单安全的注册登录页面了,而不去纠结于各项安全设置和各种接口的设计。

SpringSecurity+Mybatis实现用户自助注册登录(含角色),打造简单安全的注册登录页面。相关推荐

  1. mysql PHP注册代码_求分享简单的php注册+mysql数据库登录源码

    [PHP] 纯文本查看 复制代码HTML代码: 登录注册注销 //登录模态框 aria-hidden="true"> ×Close 请登录 用户名: pattern=&quo ...

  2. 用谷歌按钮登录_使用非常简单的设置即可登录Google的按钮

    用谷歌按钮登录 vue-google-login (vue-google-login) Button to login with google with really simple setup. 使用 ...

  3. python 通登录银行_Python3实现简单的银行账户登录系统实例

    下面小编就为大家带来一篇Python3 适合初学者学习的银行账户登录系统实例.小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧 一.所用知识点: 1. for循环与if判断 ...

  4. [OAuth2.0三方登录系列文章-1]OAuth2.0与三方登录的端到端方案

    系列文章 [OAuth2.0三方登录系列文章-1]OAuth2.0与三方登录的端到端方案 [OAuth2.0三方登录系列文章-2]如何设计基于OAuth2.0的授权登录SDK以及竞品分析 [OAuth ...

  5. 数据库用户表结构设计-多种注册方式含第三方登录

    传统互联网已经过渡到移动互联网的时代,我们在开发android.ios.小程序等的时候,客户端的注册方式已经非常的丰富多样.所以,后台的用户表的设计也需要适应不同注册方式「不断扩张」及「相互绑定」的情 ...

  6. springboot+springsecurity+mybatis plus之用户授权

    文章目录 前言 一.导入坐标 二.Users实体类及其数据库表的创建 三.controller,service,mapper层的实现 四.核心--编写配置文件 五.无权限界面和登录界面的实现 前言 即 ...

  7. java注册用户代码_java用户管理注册功能 含前后台代码

    本文实例为大家分享了java用户注册功能,供大家参考,具体内容如下 主页面: 浏览器显示: 代码实现: 用户信息管理 用户注册: 姓名: 密码: 查看所有用户 注册功能: 浏览器显示: 1)注册成功: ...

  8. springboot+springsecurity+mybatis plus注解实现对方法的权限处理

    文章目录 接上文 [springboot+springsecurity+mybatis plus之用户授权](https://blog.csdn.net/Kevinnsm/article/detail ...

  9. 用HTML做一个简单的web登录页面,简单的JavaWeb注册登录案例

    简单的JavaWeb注册登录案例 1.注册页面register.html register 姓名: 电话: 邮箱: qq: 2.注册案例实现程序register.java /** * 注册案例实现程序 ...

最新文章

  1. 百度之星2014资格赛 1004 - Labyrinth
  2. 各种格式的视频播放的代码(wma格式)
  3. c语言影碟出租程序设计总结,vc++影碟出租系统的设计与开发
  4. mysql 基本使用教程(源于网络)
  5. 百度地图的实现,IIS6.0,.net4.0 无法使用POST和GET
  6. 【Clickhouse】Clickhouse 外部存储引擎之 hdfs
  7. Java内存优化和性能优化的几点建议
  8. 线性回归 最小二乘推导
  9. listbox里面添加WrapPanel ,支持自适应换行
  10. mysql 数据库和实例_mysql中数据库和数据库实例的概念区别
  11. Matlab神经网络(一)
  12. 12星座的出生年月日性格_12星座出生日期性格特点
  13. Ubiquitous Religions(POJ并查集板子题)
  14. sklearn.neighbors.KNeighborsClassifier()函数解析(最清晰的解释)
  15. 制程与良率,谁才是芯片厂商的竞赛底牌?
  16. Python游戏开发工程师的起步,几款游戏开发案例
  17. 技术科普 | 平台调试-自动曝光(AE)
  18. 机器学习入门学习笔记(三)决策树
  19. 【八】 H.266/vvc中对称MVD模式(SMVD)
  20. 苹果备忘录误删了怎么恢复?3个方法快速复原

热门文章

  1. 培训机构靠谱吗?|猿代码科技
  2. Python openpyxl下载和安装
  3. vue-seamless-scroll的使用以及实例
  4. 摄像头 虚拟服务器页面,虚拟云服务器能调用本地摄像头
  5. 软件:分享六款实用的软件,每一款值得收藏
  6. 采用亥姆霍兹线圈进行稀土永磁性能测量
  7. JS数组转字符串传到JAVA后端取出
  8. Oracle中to_char函数的速度问题
  9. PHP论坛开发技术总结
  10. c# serialPort.DataReceived无法被触发接收数据