springboot+springsecurity+thymeleaf+mybatis整合

springboot+springsecurity+thymeleaf+mybatis整合

首先我们要考虑的是如何将springsecurity自带的用户类UserDetails 与我们项目的用户类绑定起来
方式一:重写UserDetailsService的loadUserByUsername,通过在数据库查寻到的数据为springsecurity自带的用户类UserDetails赋值,参考SpringSecurity使用 中的“通过数据库授权”
方式二:就是让系统的用户类继承springsecurity自带的用户类UserDetails,也就是本文使用的方式

数据库建模

用户表sys_user
springboot+springsecurity+thymeleaf+mybatis整合
角色表sys_role
springboot+springsecurity+thymeleaf+mybatis整合
用户和角色的联系表sys_user_role
springboot+springsecurity+thymeleaf+mybatis整合

创建项目

添加pom.xml依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.1</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>springbootdome2</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springbootdome2</name>
	<description>Demo project for Spring Boot</description>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-validation</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<!--mysql数据库驱动-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<!--mybatis-->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.0</version>
		</dependency>
		<!-- mybatis逆向工程jar包 -->
		<dependency>
			<groupId>org.mybatis.generator</groupId>
			<artifactId>mybatis-generator-core</artifactId>
			<version>1.3.4</version>
		</dependency>

		<!--security认证授权-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<!--thymeleaf引擎模板-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>

		<!--对Thymeleaf添加Spring Security标签支持-->
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-springsecurity5</artifactId>
		</dependency>

		<dependency>
			<groupId>org.webjars</groupId>
			<artifactId>jquery</artifactId>
			<version>3.5.1</version>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.mybatis.generator</groupId>
				<artifactId>mybatis-generator-maven-plugin</artifactId>
				<version>1.3.2</version>
				<configuration>
					<overwrite>true</overwrite>
					<!--逆向工程generatorConfig.xml文件位置-->
					<configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

配置项目

server.port=8081
#数据库连接配置
spring.datasource.url=jdbc:mysql://ip:3306/sweetinn?characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=用户名
spring.datasource.password=密码

#mybatis整合
mybatis.type-aliases-package=com.example.demo.pojo
mybatis.mapper-locations= classpath:mapper/*.xml
logging.level.com.example.demo.dao=debug

#关闭thymeleaf缓存
spring.thymeleaf.cache=false

创建实体类

创建用户类SysUser并继承springsecurity中的UserDetails重写方法

package com.example.demo.pojo;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;

public class SysUser implements UserDetails {
    public SysUser() {
    }
    public SysUser(String username, String password, Boolean isenable, List<? extends GrantedAuthority> authorities, String realName, String createTime, String loginTime) {
        this.username = username;
        this.password = password;
        this.isenable = isenable;
        this.authorities = authorities;
        this.realName = realName;
        this.createTime = createTime;
        this.loginTime = loginTime;
    }

    private Integer id;
    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;


    /**
     * 是否可用
     */
    private Boolean isenable;

    /**
     *用户所拥有的权限
     */
    private List<? extends GrantedAuthority> authorities;

    /**
     * 用户的账号是否过期,过期的账号无法通过授权验证. true 账号未过期
     */
    private Boolean accountNonExpired = true;

    /**
     * 用户的账户是否被锁定,被锁定的账户无法通过授权验证. true 账号未锁定
     */
    private Boolean islock = true;

    /**
     * 用户的凭据(pasword) 是否过期,过期的凭据不能通过验证. true 没有过期,false 已过期
     */
    private Boolean iscredentials = true;


    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

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

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

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

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


    private String realName;

    private String createTime;

    private String loginTime;


    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 void setIsenable(Boolean isenable) {
        this.isenable = isenable;
    }

    public void setAuthorities(List<? extends GrantedAuthority> authorities) {
        this.authorities = authorities;
    }

    public void setAccountNonExpired(Boolean accountNonExpired) {
        this.accountNonExpired = accountNonExpired;
    }

    public void setIslock(Boolean islock) {
        this.islock = islock;
    }

    public void setIscredentials(Boolean iscredentials) {
        this.iscredentials = iscredentials;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }

    public void setLoginTime(String loginTime) {
        this.loginTime = loginTime;
    }

    public Integer getId() {
        return id;
    }

    public Boolean getIsenable() {
        return isenable;
    }

    public String getRealName() {
        return realName;
    }

    public String getCreateTime() {
        return createTime;
    }

    public String getLoginTime() {
        return loginTime;
    }
}

创建角色类SysRole

package com.example.demo.pojo;

public class SysRole {
    private Integer id;
    private String roleName;
    private String roleMemo;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getRoleMemo() {
        return roleMemo;
    }
    public void setRoleMemo(String roleMemo) {
        this.roleMemo = roleMemo;
    }
}

创建dao(mapper)层

SysUserMapper

@Repository
public interface SysUserMapper {
    int insertSysUser(SysUser record);
    SysUser findSysUser(String username);
}

SysUserMapper.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.example.demo.dao.SysUserMapper" >
    <resultMap id="SysUserResultMap" type="com.example.demo.pojo.SysUser" >
        <!--
          WARNING - @mbggenerated
          This element is automatically generated by MyBatis Generator, do not modify.
        -->
        <id column="id" property="id"/>
        <result column="user_name" property="username"/>
        <result column="password" property="password"/>
        <result column="real_name" property="realName"/>
        <result column="isenable" property="isenable"/>
        <result column="islock" property="islock"/>
        <result column="iscredentials" property="iscredentials"/>
        <result column="create_time" property="createTime"/>
        <result column="login_time" property="loginTime"/>
    </resultMap>
    <insert id="insertSysUser" parameterType="com.example.demo.pojo.SysUser">
        INSERT INTO sys_user (user_name,password,real_name,isenable,islock,iscredentials,create_time,login_time)
        VALUES (#{username},#{password},#{realName},#{isenable},#{islock},#{iscredentials},#{createTime},#{loginTime})
    </insert>
    <select id="findSysUser" resultMap="SysUserResultMap">
            SELECT id,user_name,password,real_name,isenable,islock,iscredentials,create_time,login_time
            FROM sys_user
            where user_name=#{username}
    </select>
</mapper>

SysRoleMapper

@Repository
public interface SysRoleMapper {
        List<SysRole> findRoleByUserId(Integer userId);
}

SysRoleMapper.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.example.demo.dao.SysRoleMapper" >
    <resultMap id="SysRoleResultMap" type="com.example.demo.pojo.SysRole" >
        <id column="id" property="id" />
        <result column="role_name" property="roleName"/>
        <result column="role_memo" property="roleMemo"/>
    </resultMap>
    <select id="findRoleByUserId" resultMap="SysRoleResultMap">
          SELECT r.id,r.role_name,r.role_memo
          FROM sys_user_role  ur,sys_role r
          WHERE  ur.role_id=r.id and ur.user_id=#{userId}
    </select>
</mapper>

自定义UserDetailsService的子类

@Service("jdbcUserDetailService")
public class JdbcUserDetailService implements UserDetailsService {
    @Autowired
    SysUserMapper sysUserMapper;
    @Autowired
    SysRoleMapper sysRoleMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
         
        SysUser sysUser = sysUserMapper.findSysUser(username);
        if(sysUser!=null){
            List<SysRole> roleByUserId = sysRoleMapper.findRoleByUserId(sysUser.getId());
            List<GrantedAuthority> list=new ArrayList<>();
            for (SysRole sysRole:roleByUserId) {
                GrantedAuthority grantedAuthority=new SimpleGrantedAuthority("ROLE_"+sysRole.getRoleName());
                list.add(grantedAuthority);
            }
            sysUser.setAuthorities(list);
        }
        return sysUser;
    }
}

配置springsecurity

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    @Qualifier(value = "jdbcUserDetailService")
    UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

    //认证
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/","/index","/toLogin","/login").permitAll()
                .antMatchers("/level1/**").hasRole("level1")
                .antMatchers("/level2/**").hasRole("level2")
                .antMatchers("/level3/**").hasRole("level3");
        http.formLogin().loginPage("/toLogin")  //指定自定义的登录页面
                .usernameParameter("name")      //指定自定义的登录页面用户名
                .passwordParameter("passwd")    //指定自定义的登录页面密码
                .loginProcessingUrl("/toLogin");//表单提交的路径
        http.csrf().disable();
    }
}

启动类

@MapperScan("com.example.demo.dao")//启动项目时扫描dao层接口
@SpringBootApplication
public class Springbootdome2Application {
    @Autowired
    SysUserMapper sysUserMapper;
	public static void main(String[] args) {
		SpringApplication.run(Springbootdome2Application.class, args);
	}
	
 //启动项目时向数据库用户表添加用户
/*	@PostConstruct
	public void jdbcInit(){
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        List<GrantedAuthority> list=new ArrayList<>();
        SysUser sysUser = new SysUser("root",encoder.encode("123456"),true,list,"root","2021-02-25","2021-02-25");
        sysUserMapper.insertSysUser(sysUser);
	}*/
}

前端页面

springboot+springsecurity+thymeleaf+mybatis整合
mylogin.html

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>

<div style="text-align: center">
    登录
    <form th:action="@{/toLogin}" method="post">
        登录名:<input name="name" /> <br/>
        密码:<input type="password" name="passwd"/><br/>
       <input type="checkbox" name="jzw"> 记住我<br/>
        <input type="submit" />
    </form>
</div>

</body>
</html>

home.html

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <div sec:authorize="!isAuthenticated()">
    <a th:href="@{/toLogin}">登录</a>
    </div>

    <div sec:authorize="isAuthenticated()">
        用户名:<span sec:authentication="principal.username"></span>
        角色:<span sec:authentication="principal.authorities"></span>
        <a th:href="@{/logout}">注销</a>
    </div>
</div>
<div sec:authorize="hasRole('level1')">
<a th:href="@{/level1/page/1}">level1-page1</a>
<a th:href="@{/level1/page/2}">level1-page2</a>
<a th:href="@{/level1/page/3}">level1-page3</a>
</div>
<div sec:authorize="hasRole('level2')">
    <a href="/level2/page/1">level2-page1</a>
    <a href="/level2/page/2">level2-page2</a>
    <a href="/level2/page/3">level2-page3</a>
</div>
<div sec:authorize="hasRole('level3')">
    <a href="/level3/page/1">level3-page1</a>
    <a href="/level3/page/2">level3-page2</a>
    <a href="/level3/page/3">level3-page3</a>
</div>
</body>
</html>

补充:1.数据库的用户密码加密方式必须和springsecurity的认证授权加密方式一致
2.数据库数据
springboot+springsecurity+thymeleaf+mybatis整合
springboot+springsecurity+thymeleaf+mybatis整合
springboot+springsecurity+thymeleaf+mybatis整合

上一篇:SpringBoot+JPA+thymeleaf 菜单分级展示


下一篇:Springboot 邮件发送实例