Spring Security实现JDBC用户登录认证
在搭建博客后端服务框架时,我采用邮件注册+Spring Security登录认证方式,结合mysql数据库,给大家展示下具体是怎么整合的。
本篇是基于上一篇:spring boot实现邮箱验证码注册
1.引入Spring Security相关依赖
<!--spring 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>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.2.RELEASE</version>
</dependency>
2.添加相关页面
2.1 login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}" style="color: red;">
用户名或密码错误!
</div>
<div th:if="${param.logout}" style="color: darkgreen;">
注销成功!
</div>
<form th:action="@{/login}" method="post">
<div><label> 用户名 : <input type="text" name="username"/> </label></div>
<div><label> 密码: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="submit"/> <input type="reset" value="reset"/></div>
</form>
<p>Click <a th:href="@{/welcome}">here</a> go to home page.</p>
</body>
</html>
3.创建User表及实体类
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`active_code` varchar(100) DEFAULT NULL,
`active_status` int(11) DEFAULT '0',
`roles` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
package com.laoxu.easyblog.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @description: 用户
* @author: luohanye
* @create: 2019-04-17
**/
@Data
public class User implements Serializable {
private Integer id;
private String username;
private String password;
private String email;
// 激活状态 0 未激活 1 已激活
private Integer activeStatus;
// 激活码
private String activeCode;
// 角色
private String roles;
}
4.创建自定义UserDetailService实现类
package com.laoxu.easyblog.service;
import com.laoxu.easyblog.dao.UserDao;
import com.laoxu.easyblog.entity.User;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 自定义UserService
*/
@Service
public class MyUserService<T extends User> implements UserDetailsService {
@Autowired
private UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
try {
User user = userDao.selectByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户名不存在");
}
//用户权限
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
if (StringUtils.isNotBlank(user.getRoles())) {
String[] roles = user.getRoles().split(",");
for (String role : roles) {
if (StringUtils.isNotBlank(role)) {
authorities.add(new SimpleGrantedAuthority(role.trim()));
}
}
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
5.创建MD5工具类
package com.laoxu.easyblog.common;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* md5工具类
*/
public class MD5Util {
public static final int time = 5;
public static final String SALT = "springsecurity";
/**
* 密码加密方法
*
* @param password
* @return
*/
public static String encode(String password) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("MD5 algorithm not available. Fatal (should be in the JDK).");
}
try {
for (int i = 0; i < time; i++) {
byte[] bytes = digest.digest((password + SALT).getBytes("UTF-8"));
password = String.format("%032x", new BigInteger(1, bytes));
}
return password;
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("UTF-8 encoding not available. Fatal (should be in the JDK).");
}
}
public static void main(String[] args) {
System.out.println(MD5Util.encode("123456"));
}
}
6.创建自定义密码验证类
package com.laoxu.easyblog.common;
import org.springframework.security.crypto.password.PasswordEncoder;
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return MD5Util.encode((String) rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
//user Details Service验证
return encodedPassword.equals(MD5Util.encode((String) rawPassword));
}
}
7.添加Spring Security配置
package com.laoxu.easyblog.config;
import com.laoxu.easyblog.common.MyPasswordEncoder;
import com.laoxu.easyblog.entity.User;
import com.laoxu.easyblog.service.MyUserService;
import org.springframework.beans.factory.annotation.Autowired;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
* Spring Security配置
*
* @author xusucheng
* @create 2018-10-26
**/
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
/* @Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}*/
@Resource
private MyUserService<User> userService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(new MyPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/css/**", "/js/**", "/fonts/**", "/images/**").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/welcome").hasRole("ADMIN")
.and().formLogin().loginPage("/login").permitAll().defaultSuccessUrl("/welcome")
.and().logout().permitAll()
;
}
@Override
public void configure(WebSecurity web) throws Exception {
//忽略
web.ignoring().antMatchers("/wd/**");
}
}
8.配置视图转发器
package com.laoxu.easyblog.config;
import com.laoxu.easyblog.interceptor.LoginHandlerInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
/**
* @author xusucheng
* @create 2018-10-23
**/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Value("${spring.mvc.view.prefix}")
private String prefix="";
@Value("${spring.mvc.view.suffix}")
private String suffix="";
@Value("${spring.mvc.view.view-name}")
private String viewName="";
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/static/assets/");
registry.addResourceHandler("/wd/**").addResourceLocations("classpath:/wd/");
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.addViewController("/welcome").setViewName("welcome");
}
@Bean
public InternalResourceViewResolver jspViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(prefix);
resolver.setSuffix(suffix);
resolver.setViewClass(JstlView.class);
resolver.setViewNames(viewName);
return resolver;
}
/* @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**").excludePathPatterns("/login","/register","/assets/**","/wd/**","/account/changePwd","/account/add");
}*/
}
9.测试
9.1 注册账号
访问:localhost:8080 先注册一个账号,例如:lisi 123
9.2 激活账号
9.3 登录失败,没有ROLE_ADMIN权限
9.4 登录成功,添加用户权限为ROLE_ADMIN
分类:
Java项目实战
, # Spring-Boot
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构