Spring?Security實現(xiàn)用戶名密碼登錄詳解
環(huán)境
JDK 1.8
Spring Boot 2.3.0.RELEASE
Maven 3.6.1
H2 數(shù)據(jù)庫
用戶名密碼登錄
首先,我們用 Spring Security 實現(xiàn)用戶輸入用戶名密碼登錄驗證并獲取相應(yīng)權(quán)限。
E-R圖

完整建表語句
因為是測試程序,所以用H2數(shù)據(jù)庫來測試。SQL腳本在resouces/db目錄下,項目啟動后會自動初始化腳本,無需手動執(zhí)行。
schema.sql
DROP TABLE IF EXISTS `SYS_ROLE`;
DROP TABLE IF EXISTS `SYS_USER_ROLE`;
DROP TABLE IF EXISTS `SYS_USER`;
create table SYS_ROLE
(
ID INT not null primary key,
NAME VARCHAR(255) not null
);
create table SYS_USER
(
ID INT not null primary key,
NAME VARCHAR not null,
PASSWORD VARCHAR(255) not null
);
create table SYS_USER_ROLE
(
USER_ID INT not null,
ROLE_ID INT not null,
constraint pk_1 primary key (ROLE_ID, USER_ID),
constraint fk_1 foreign key (ROLE_ID) references SYS_ROLE (ID) on update cascade on delete cascade,
constraint fk_2 foreign key (USER_ID) references SYS_USER (ID) on update cascade on delete cascade
);
data.sql
INSERT INTO `SYS_ROLE` (`ID`, `NAME`) VALUES (1, 'ADMIN'),(2, 'USER'); INSERT INTO `SYS_USER` (`ID`, `NAME`, `PASSWORD`) VALUES (1, 'super', '888888'), (2, 'jack', '666666'), (3, 'lucy', '999999'); INSERT INTO `SYS_USER_ROLE` (`USER_ID`, `ROLE_ID`) VALUES (1, 1),(2, 2),(3, 2);
準備好建表語句后,完成實體類的編寫
SysRole.java
package org.hui.login.model;
/**
* 用戶角色
* @author zenghui
* @date 2020-05-20
*/
public class SysRole {
private Integer id;
private String name;
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;}
}
SysUser.java
package org.hui.login.model;
/**
* 用戶基本信息
* @author zenghui
* @date 2020-05-20
*/
public class SysUser {
private Integer id;
private String name;
private String password;
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 getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
}
SysUserRole.java
package org.hui.login.model;
/**
* 角色和用戶對應(yīng)關(guān)系
* @author zenghui
* @date 2020-05-20
*/
public class SysUserRole {
private Integer userId;
private Integer roleId;
public Integer getUserId() {return userId;}
public void setUserId(Integer userId) {this.userId = userId;}
public Integer getRoleId() {return roleId;}
public void setRoleId(Integer roleId) {this.roleId = roleId;}
}
以上,完成了數(shù)據(jù)層的設(shè)計。
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 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.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>example</groupId>
<artifactId>spring-login</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-login</name>
<description>Spring Security to implements Login</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置文件
application.properties
spring.datasource.url=jdbc:h2:mem:userdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=123 #設(shè)置SQL腳本的位置,resources/db目錄下,如果不設(shè)置的話,默認就在resources目錄下 spring.datasource.schema=classpath:db/schema.sql spring.datasource.data=classpath:db/data.sql #H2控制臺啟用 spring.h2.console.enabled=true #訪問H2的URL spring.h2.console.path=/h2 # 下劃線轉(zhuǎn)化為駝峰命名 mybatis.configuration.map-underscore-to-camel-case=true
Mapper
采用了Mybatis來操作數(shù)據(jù)庫。
準備好需要的幾個Mapper,如下
SysRoleMapper.java
package org.hui.login.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.hui.login.model.SysRole;
/**
* @author zenghui
* @date 2020-05-20
*/
@Mapper
public interface SysRoleMapper {
@Select("SELECT * FROM sys_role WHERE id = #{id}")
SysRole selectById(Integer id);
}SysUserMapper.java
package org.hui.login.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.hui.login.model.SysUser;
/**
* @author zenghui
* @date 2020-05-20
*/
@Mapper
public interface SysUserMapper {
@Select("SELECT * FROM sys_user WHERE name = #{name}")
SysUser selectByName(String name);
}
SysUserRoleMapper.java
package org.hui.login.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.hui.login.model.SysUserRole;
import java.util.List;
/**
* @author zenghui
* @date 2020-05-20
*/
@Mapper
public interface SysUserRoleMapper {
@Select("SELECT * FROM sys_user_role WHERE user_id = #{userId}")
List<SysUserRole> listByUserId(Integer userId);
}
Service設(shè)計
Spring Security提供了一個UserDetailsService接口,我們需要實現(xiàn)這個接口的loadUserByUsername方法,用于用戶信息的獲取,如果存在用戶,則把用戶的密碼獲取出來,如果不存在這個用戶,直接拋異常。
我們新建一個SysUserDetailService.java
package org.hui.login.service;
import org.hui.login.mapper.SysRoleMapper;
import org.hui.login.mapper.SysUserMapper;
import org.hui.login.mapper.SysUserRoleMapper;
import org.hui.login.model.SysRole;
import org.hui.login.model.SysUser;
import org.hui.login.model.SysUserRole;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author zenghui
* @date 2020-05-20
*/
@Service
public class SysUserDetailService implements UserDetailsService {
private final SysUserMapper sysUserMapper;
private final SysRoleMapper sysRoleMapper;
private final SysUserRoleMapper sysUserRoleMapper;
public SysUserDetailService(SysUserMapper sysUserMapper, SysRoleMapper sysRoleMapper, SysUserRoleMapper sysUserRoleMapper) {
this.sysUserMapper = sysUserMapper;
this.sysRoleMapper = sysRoleMapper;
this.sysUserRoleMapper = sysUserRoleMapper;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Collection<GrantedAuthority> authorities = new ArrayList<>();
// 從數(shù)據(jù)庫中取出用戶信息
SysUser user = sysUserMapper.selectByName(username);
// 判斷用戶是否存在
if(user == null) {
throw new UsernameNotFoundException("用戶名不存在");
}
// 添加權(quán)限
List<SysUserRole> userRoles = sysUserRoleMapper.listByUserId(user.getId());
for (SysUserRole userRole : userRoles) {
SysRole role = sysRoleMapper.selectById(userRole.getRoleId());
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
// 返回UserDetails實現(xiàn)類
return new User(user.getName(), user.getPassword(), authorities);
}
}
如果用戶存在,則會進行密碼的校驗,方便起見,密碼我們假設(shè)儲存為明文,實際上密碼有很多加密的策略,這個后序可以自己配置,密碼校驗在SecurityConfig這個類中,代碼如下:
package org.hui.login.config;
import org.hui.login.service.SysUserDetailService;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author zenghui
* @date 2020-05-20
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final SysUserDetailService sysUserDetailService;
public SecurityConfig(SysUserDetailService sysUserDetailService) {
this.sysUserDetailService = sysUserDetailService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(sysUserDetailService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
});
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().formLogin().loginPage("/login").defaultSuccessUrl("/").permitAll()
.and().logout().permitAll();
// 關(guān)閉CSRF跨域
http.csrf().disable();
}
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/css/**", "/js/**");
}
}
以上便完成了所有后端代碼的編寫,接下來,完成controller和前端頁面的編寫。
HTML
在resources的static目錄下,新建兩個html文件
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登錄頁</title>
</head>
<body>
<form action="/login" method="post">
用戶名:<input type="text" name="username">
密碼:<input type="password" name="password">
<button type="submit">登錄</button>
</form>
</body>
</html>
home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主頁</title>
</head>
<body>
登錄成功
</body>
</html>
Controller
新建一個LoginController,用于接收前端請求
package org.hui.login.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author zenghui
* @date 2020-05-20
*/
@Controller
public class LoginController {
@RequestMapping("/")
public String home() {
return "home.html";
}
@RequestMapping("/login")
public String login() {
return "login.html";
}
}
啟動
運行以下主程序
package org.hui.login;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author zenghui
* @date 2020-05-20
*/
@SpringBootApplication
public class LoginApplication {
public static void main(String[] args) {
SpringApplication.run(LoginApplication.class, args);
}
}
訪問 http://localhost:8080/login
顯示登錄頁面,輸入用戶名密碼,點擊登錄,即可看到效果。
完整代碼
以上就是Spring Security實現(xiàn)用戶名密碼登錄詳解的詳細內(nèi)容,更多關(guān)于Spring Security用戶名密碼登錄的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
spring源碼學(xué)習(xí)之bean的初始化以及循環(huán)引用
這篇文章主要給大家介紹了關(guān)于spring源碼學(xué)習(xí)之bean的初始化以及循環(huán)引用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
火遍全網(wǎng)的Hutool使用Builder模式創(chuàng)建線程池的方法
這篇文章主要介紹了火遍全網(wǎng)的Hutool使用Builder模式創(chuàng)建線程池的方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03
性能爆棚的實體轉(zhuǎn)換復(fù)制工具MapStruct使用詳解
這篇文章主要為大家介紹了性能爆棚的實體轉(zhuǎn)換復(fù)制工具MapStruct使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03
Mybatis-Plus實體類注解方法與mapper層和service層的CRUD方法
CRUD是指在做計算處理時的增加(Create)、讀取查詢(Retrieve)、更新(Update)和刪除(Delete)幾個單詞的首字母簡寫。主要被用在描述軟件系統(tǒng)中DataBase或者持久層的基本操作功能,下面讓我們一起看看吧2022-03-03
帶你走進Maven的大門-最全Maven配置及集成idea工具總結(jié)
Maven項目對象模型(POM),是一個項目管理工具可以通過一小段描述信息來管理項目的構(gòu)建,報告和文檔的軟件.那我們想要在IDEA中使用Maven得進行一些配置,接下來我們具體看一下是如何配置使用的,需要的朋友可以參考下2021-06-06
使用Spring Security集成手機驗證碼登錄功能實現(xiàn)
本文詳細介紹了如何利用SpringSecurity來實現(xiàn)手機驗證碼的注冊和登錄功能,在登錄過程中,同樣需通過驗證碼進行驗證,文章還提供了相關(guān)的代碼實現(xiàn)2024-10-10

