SpringSecurity+thymeleaf+Mybatis+SpringBoot实现登陆功能
最近学习了SpringSecurity就写一个小小的demo来练习一下,如果帮到你了请点一个赞。
如果有错误的地方一定一定要指出来,万分感谢
1.创建一个非常简单的表
super代表超级管理员的一个权限。
2.引入相关的依赖(springboot的基本依赖没有写)
<!--springsecurity-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.4.5</version>
</dependency>
<!--thymeleaf模板-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
<version>3.0.1.RELEASE</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
2.编写yml配置文件
#连接数据库
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/mall?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
mapper-locations: classpath:mapper/*.xml
如果Mapper.xml与Mapper.class不在同一个包下或者不同名,就必须使用配置mapperLocations指定mapper.xml的位置。
3.在创建的mapper包下创建名字为AdminLoginMapper的接口
package com.taobao.mapper;
import com.taobao.pojo.Admin;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Repository
@Mapper
public interface AdminLoginMapper {
Admin adminLogin(String admin_account);
}
4.编写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.taobao.mapper.AdminLoginMapper">
<select id="adminLogin" parameterType="String" resultType="com.taobao.pojo.Admin">
SELECT * FROM admin WHERE admin_account = #{admin_account}
</select>
</mapper>
至此关于mybatis的操作完成,本文着重与SpringSecurity就不在对mybatis做详细的讲解了。
5.在resoueces的static下引入静态资源 css js等。
6.在resoueces的template下创建一个login.html登录页。
<!doctype html>
<html class="x-admin-sm" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>后台登录</title>
<meta name="renderer" content="webkit|ie-comp|ie-stand">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width,user-scalable=yes, minimum-scale=0.4, initial-scale=0.8,target-densitydpi=low-dpi" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
<link rel="stylesheet" th:href="@{/css/font.css}">
<link rel="stylesheet" th:href="@{/css/login.css}">
<link rel="stylesheet" th:href="@{/css/xadmin.css}">
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="/lib/layui/layui.js" charset="utf-8"></script>
<!--[if lt IE 9]>
<script src="https://cdn.staticfile.org/html5shiv/r29/html5.min.js"></script>
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body class="login-bg">
<div class="login layui-anim layui-anim-up">
<div class="message">管理登录</div>
<div id="darkbannerwrap"></div>
<form method="post" class="layui-form" th:action="@{/login}">
<input name="username" placeholder="用户名" type="text" lay-verify="required" class="layui-input" >
<hr class="hr15">
<input name="password" lay-verify="required" placeholder="密码" type="password" class="layui-input">
<hr class="hr15">
<input value="登录" lay-submit lay-filter="login" style="width:100%;" type="submit">
<hr class="hr20" >
</form>
</div>
</body>
</html>
这里我用的x-admin模板,不用重点关注只需要关注form表单即可。th:action=“@{}”是thymeleaf中的写法,这里也不做过多讲解。
/login下面会做解释。这里的表单提交方式必须为post,账号密码的属性值必须为uername和password下面会做解释
7.创建实体类
package com.taobao.pojo;
public class Admin {
private Integer id;
private String admin_account;
private String admin_password;
private String leavl;
public Admin() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAdmin_account() {
return admin_account;
}
public void setAdmin_account(String admin_account) {
this.admin_account = admin_account;
}
public String getAdmin_password() {
return admin_password;
}
public void setAdmin_password(String admin_password) {
this.admin_password = admin_password;
}
public String getLeavl() {
return leavl;
}
public void setLeavl(String leavl) {
this.leavl = leavl;
}
@Override
public String toString() {
return "Admin{" +
"id=" + id +
", admin_account='" + admin_account + '\'' +
", admin_password='" + admin_password + '\'' +
", leavl='" + leavl + '\'' +
'}';
}
}
8.编写SpringSecurity的配置
a.使用@EnableWebSecurity注解,开启Security同时说明这个Configuration类。
b.继承WebSecurityConfigurerAdapter这个类
c.重写configure(HttpSecurity http) 和 configure(HttpSecurity http) 两个方法
package com.taobao.security;
import org.springframework.beans.factory.annotation.Autowired;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//下面会讲到,别急
@Autowired
private UserDetailsService userDetailsService;
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
//自定义的登录页面,不写这个会跳到SpringSecurity自己内置的登录页面
.loginPage("/AdminLogin")
.loginProcessingUrl("/user/login")
.defaultSuccessUrl("/admin/index").permitAll()
//任何请求都需要授权
.and().authorizeRequests()
.antMatchers("/","/user/login").permitAll()
.antMatchers("/admin/index").hasAnyAuthority("super")
//任何请求都不需要授权
.anyRequest().authenticated()
//关闭csrf防护
.and().csrf().disable();
}
//认证
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//在数据库中获取数据,对密码进行验证,不对密码加密会报错。
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
}
9.创建一个service类实现UserDetailsService接口
package com.taobao.service.impl;
import com.taobao.mapper.AdminLoginMapper;
import com.taobao.pojo.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
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实现UserDetailsService接口
@Service("userDetailsService")
public class AdminDetailsServiceImpl implements UserDetailsService {
@Autowired
private AdminLoginMapper adminLoginMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
//通过用户名在数据库中查询
Admin admin = adminLoginMapper.adminLogin(s);
//如果admin为空说明用户名错误,抛出一个异常
if(admin==null){
throw new UsernameNotFoundException("用户名不存在!");
}
//获取该账号的权限
List<GrantedAuthority> atuhs = AuthorityUtils.commaSeparatedStringToAuthorityList(admin.getLeavl());
//查询数据库返回的user对象,密码认证交给security做,密码必须加密。
return new User(admin.getAdmin_account(),new BCryptPasswordEncoder().encode(admin.getAdmin_password()),atuhs);
}
}
这个类就是我们上面@Autowired的内个类
关于.loginProcessingUrl("/login")的意思登陆访问路径:提交表单之后跳转的地址,可以看作一个中转站,这个步骤就是验证user的一个过程
我的理解是 表单提交到一个controller 这个controller应该调用AdminDetailServiceImpl 。但是这个过程security已经帮我们做了,这里随便写一个地址就好了只需要和action中的保持一直
关于defaultSuccessUrl();百度了一下得到了以下的答案:(原文链接:https://www.xttblog.com/?p=4994)
其实我们通过 defaultSuccessUrl 和 successForwardUrl 的字面意思都能够理解他们的作用。
defaultSuccessUrl 有一个重载的方法,如果我们在 defaultSuccessUrl 中指定登录成功的跳转页面为 /index,此时分两种情况,如果你是直接在浏览器中输入的登录地址,登录成功后,就直接跳转到 /index,如果你是在浏览器中输入了其他地址,例如 http://localhost:8080/xttblog,结果因为没有登录,又重定向到登录页面,此时登录成功后,就不会来到 /index ,而是来到 /xttblog 页面。
defaultSuccessUrl 就是说,它会默认跳转到 Referer 来源页面,如果 Referer 为空,没有来源页,则跳转到默认设置的页面。
successForwardUrl 表示不管你是从哪里来的,登录后一律跳转到 successForwardUrl 指定的地址。例如 successForwardUrl 指定的地址为 /index ,你在浏览器地址栏输入 http://localhost:8080/codedq,如果你还没有登录,将会重定向到登录页面,当你登录成功之后,就会服务端跳转到 /index 页面;或者你直接就在浏览器输入了登录页面地址,登录成功后也是来到 /index。
defaultSuccessUrl 另外一个重载方法,第二个参数如果输入为 true,则效果和 successForwardUrl 一致。
一般来说,我们使用 defaultSuccessUrl 就够了。而且体验也比较好,特殊情况下,我们才使用 successForwardUrl。
loginPage源码的注释中已经说明,login.html 配置提交请求及方式,方式必须为post:
看User类的源码可以知道form表单的账号密码属性必须是username,password.
本人功力尚浅,道行不够。写的还不尽如人意,大家请见谅,对于错误的地方大家一定要给我指出来,我会虚心接收。谢谢