1.创建一个springboot 的demo
我使用的是Eclipse 创建的项目 springboot 版本 2.16
创建项目.png
2.添加数据源
pom 文件
<!-- 使用阿里巴巴的数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
将application.properties 改为 application.yml 并添加数据库配置
#端口号
server:
port: 80
#数据库连接
spring:
datasource:
name: demotest
url: jdbc:mysql://localhost:3306/demotest?serverTimezone=UTC
username: root
password: root
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
3.访问 http://localhost:80
密码会打印出来
image.png
登录一下
image.png
4.使用自定义的登录页面
新建SecurityConfig 类
package com.example.demo;
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 com.example.demo.auth.CaptchaDaoAuthenticationProvider;
import com.example.demo.auth.SecUserDetailsService;
import com.example.demo.repository.DmUserRepository;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
private SecUserDetailsService secUserDetailsService;
@Autowired
private DmUserRepository upmsUserRepository;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/css/**", "/index").permitAll() /*与之匹配的请求/CSS/*和/索引完全无障碍*/
.antMatchers("/user/**").hasRole("USER") /*与之匹配的请求/用户/*要求对用户进行身份验证,并且必须与用户角色*/
.and().formLogin()
.loginPage("/login").failureUrl("/login-error"); /*基于表单的身份验证是通过自定义登录页和故障url启用的。*/
}
/**
* 使用数据库用户进行登录
* @param auth
* @throws Exception
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
CaptchaDaoAuthenticationProvider authProvider = new CaptchaDaoAuthenticationProvider();
authProvider.setUserDetailsService(secUserDetailsService);
authProvider.setUpmsUserRepository(upmsUserRepository);
auth.authenticationProvider(authProvider);
}
}
新建controller类
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
@RequestMapping("/")
public String root() {
return "redirect:/index";
}
@RequestMapping("/index")
public String index() {
return "index";
}
@RequestMapping("/user/index")
public String userIndex() {
return "user/index";
}
@RequestMapping("/login")
public String login() {
return "login";
}
@RequestMapping("/login-error")
public String loginError(Model model) {
model.addAttribute("loginError", true);
return "login";
}
}
新建用户实体类
package com.example.demo.domain;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@SuppressWarnings("serial")
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class DmUser implements Serializable {
@Id @GeneratedValue
private Integer id;
private String username;
private String showname;
private String password;
private String role;
}
新建 BaseRepository类 使用的是JPA 查询用户信息
package com.example.demo.repository;
import java.io.Serializable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
}
package com.example.demo.repository;
import org.springframework.stereotype.Repository;
import com.example.demo.domain.DmUser;
/**
* 用户管理
* @author llm
*/
@Repository
public interface DmUserRepository extends BaseRepository<DmUser, Integer> {
/**
* 根据用户名查询用户
* @param userName 用户名
* @return 用户对象。不存在则返回null
*/
DmUser findByUsername(String username);
}
验证数据库用户信息相关的类
package com.example.demo.auth;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import com.example.demo.domain.DmUser;
import com.example.demo.repository.DmUserRepository;
public class CaptchaDaoAuthenticationProvider extends DaoAuthenticationProvider {
private DmUserRepository upmsUserRepository;
public void setUpmsUserRepository(DmUserRepository upmsUserRepository) {
this.upmsUserRepository = upmsUserRepository;
}
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken token)
throws AuthenticationException {
ReflectionUserSource userSource = new ReflectionUserSource();
DmUser upmsUser = (DmUser)userSource.getUser(userDetails);
}
}
package com.example.demo.auth;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.example.demo.domain.DmUser;
/**
* 用户信息认证
* @author llm
*
*/
public class SecUserDetails implements UserDetails{
private DmUser user;
public SecUserDetails(DmUser user) {
this.user = user;
}
public DmUser getUser() {
return user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
auths.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return user.getRole();
}
});
return auths;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
package com.example.demo.auth;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.ReflectionUtils;
public class ReflectionUserSource {
private String userPropertyToUse = "user";
public Object getUser(UserDetails user) {
Method saltMethod = findSaltMethod(user);
try {
return saltMethod.invoke(user);
}
catch (Exception exception) {
throw new AuthenticationServiceException(exception.getMessage(), exception);
}
}
private Method findSaltMethod(UserDetails user) {
Method saltMethod = ReflectionUtils.findMethod(user.getClass(),
userPropertyToUse, new Class[0]);
if (saltMethod == null) {
PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(user.getClass(),
userPropertyToUse);
if (pd != null) {
saltMethod = pd.getReadMethod();
}
if (saltMethod == null) {
throw new AuthenticationServiceException(
"Unable to find user method on user Object. Does the class '"
+ user.getClass().getName()
+ "' have a method or getter named '" + userPropertyToUse
+ "' ?");
}
}
return saltMethod;
}
}
判断当前用户登录的信息
package com.example.demo.auth;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import com.example.demo.domain.DmUser;
import com.example.demo.repository.DmUserRepository;
public class CaptchaDaoAuthenticationProvider extends DaoAuthenticationProvider {
private DmUserRepository upmsUserRepository;
public void setUpmsUserRepository(DmUserRepository upmsUserRepository) {
this.upmsUserRepository = upmsUserRepository;
}
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken token)
throws AuthenticationException {
ReflectionUserSource userSource = new ReflectionUserSource();
DmUser upmsUser = (DmUser)userSource.getUser(userDetails);
//判断用户信息
}
}
页面index.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-springsecurity5">
<head>
<title>Hello Spring Security</title>
<meta charset="utf-8" />
<!-- <link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" /> -->
</head>
<body>
<div th:fragment="logout" class="logout" sec:authorize="isAuthenticated()">
用户名: <span sec:authentication="name"></span> |
角色: <span sec:authentication="principal.authorities"></span>
<div>
<form action="#" th:action="@{/logout}" method="post">
<input type="submit" value="退出" />
</form>
</div>
</div>
<h1>Hello Spring Security</h1>
<p>This is an unsecured page, but you can access the secured pages after authenticating.</p>
<ul>
<li>Go to the <a href="/user/index" th:href="@{/user/index}">secured pages</a></li>
</ul>
</body>
</html>
login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Login page</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<h1>Login page</h1>
<p>Example user: user / password</p>
<p th:if="${loginError}" class="error">Wrong user or password</p>
<form th:action="@{/login}" method="post">
<label for="username">Username</label>:
<input type="text" id="username" name="username" autofocus="autofocus" /> <br />
<label for="password">Password</label>:
<input type="password" id="password" name="password" /> <br />
<input type="submit" value="Log in" />
</form>
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
</body>
</html>
登录成功后 user/index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Hello Spring Security</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="/css/main.css" th:href="@{/css/main.css}" />
</head>
<body>
<div th:substituteby="index::logout"></div>
<h1>This is a secured page!</h1>
<p><a href="/index" th:href="@{/index}">Back to home page</a></p>
</body>
</html>
5.创建数据库用户
CREATE TABLE `dm_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`showname` varchar(255) NOT NULL,
`password` varchar(255) NOT NULL,
`role` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `dm_user` VALUES ('1', 'llm', '123456', '123456', 'ROLE_USER');
6.运行项目结果
image.png
7.项目结构
image.png
8.pom文件
<?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 http://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.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.llm</groupId>
<artifactId>ceshi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>securitydemo-1</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<!-- 使用阿里巴巴的数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
网友评论