导入依赖框架
web 框架(spring-boot-starter-web)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
springSecurity 框架(spring-boot-starter-security)
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>
导入框架之后、当前应用已经具备验证功能
-
用户名默认为user、密码为启动窗口打印信息
-
默认登陆页(存在问题、每次需要记录登录密码)
-
配置文件配置固定用户名、密码
自定义功能实现(用户信息从数据库获取)
方式一:
-
导入数据源依赖 mysql\mybatis,配置数据源信息
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.3</version></dependency>
-
直接配置查询 sql (select username,password from s_usr where username = ?)
package com.bu.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;import javax.sql.DataSource;/*** @author haizhuangbu* @date 2024/5/15 16:35* @mark WebSecurityConfigImpl*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfigImpl extends WebSecurityConfigurerAdapter {@Autowiredprivate DataSource dataSource;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.jdbcAuthentication()// 配置数据源.dataSource(dataSource)// 查询sql.usersByUsernameQuery("select username,password,'Y' enabled from s_usr where username = ?").authoritiesByUsernameQuery("select username,authority\n" +"from authorizes where username = ?");}// 不进行解密、直接对比@Beanpublic PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}}
-
此时用户信息就是去数据库查询的 (用户信息表 创建包含用户密码关键字段即可)
create table s_usr
(user_id varchar(36) not nullprimary key,username varchar(36) null,password varchar(36) null,create_time datetime null,modify_time datetime null,enable char(2) null comment 'Y 生效 N 失效'
);create table authorizes
(username varchar(36),authority varchar(36)
);insert into s_usr
values ('1', 'admin', 'admin', now(), now(), 'Y');
方式二:
-
导入数据源配置信息同方式一相同
-
重写springSecurity 的几个组件
- UserDetailsService 用户信息查询接口(内部具体编写查询逻辑 )
package com.bu.config;import com.bu.sys.user.dao.UserDetailsDao;
import com.bu.sys.user.dto.SUsrDto;
import org.springframework.beans.factory.annotation.Autowired;
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.Component;/*** @author haizhuangbu* @date 2024/5/15 16:22* @mark AuthUserServiceImpl*/
@Component
public class AuthUserServiceImpl implements UserDetailsService {@Autowiredprivate UserDetailsDao userDetailsDao;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {SUsrDto sUsrDto = userDetailsDao.findSUsrByUsername(username);return sUsrDto;}
}package com.bu.sys.user.dao;import com.bu.sys.user.dto.SUsrDto;
import org.apache.ibatis.annotations.Select;/*** @author haizhuangbu* @date 2024/5/15 17:15* @mark UserDetailsDao*/
public interface UserDetailsDao {@Select("select * from s_usr where username = #{username}")SUsrDto findSUsrByUsername(String username);}
- PasswordEncoder 加解密工具
// 不进行解密、直接对比@Beanpublic PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}
- UserDetail 用户信息
package com.bu.sys.user.dto;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection;/*** @author haizhuangbu* @date 2024/5/15 17:16* @mark SUsrDto*/
public class SUsrDto implements UserDetails {private String username;private String password;public String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;}public void setUsername(String username) {this.username = username;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return null;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
- AuthenticationProvider 验证流程
package com.bu.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
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.password.PasswordEncoder;
import org.springframework.stereotype.Component;/*** @author haizhuangbu* @date 2024/5/15 17:20* @mark UserAutorizedServiceImpl*/
@Component
public class UserAuthorizedServiceImpl implements AuthenticationProvider {@Autowiredprivate UserDetailsService userDetailsService;@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic Authentication authenticate(Authentication authentication) throws AuthenticationException {// 查询用户信息UserDetails userDetails = userDetailsService.loadUserByUsername(authentication.getName());if (userDetails == null) {throw new UsernameNotFoundException("用户信息不存在");}if (!passwordEncoder.matches(userDetails.getPassword(), (String) authentication.getCredentials())) {throw new UsernameNotFoundException("密码不正确");}return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword());}@Overridepublic boolean supports(Class<?> aClass) {return true;}
}
-
验证组件交给springSecurity (同数据源方式类似)
package com.bu.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;import javax.sql.DataSource;/*** @author haizhuangbu* @date 2024/5/15 16:35* @mark WebSecurityConfigImpl*/
@Configuration
@EnableWebSecurity
public class WebSecurityConfigImpl extends WebSecurityConfigurerAdapter {@Autowiredprivate UserAuthorizedServiceImpl userAuthorizedService;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.authenticationProvider(userAuthorizedService);}}
配置其他信息(成功跳转、失败跳转....)
// 非页面列表页可以无权限访问外、其他都需要验证@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests()// permitAll 放行路径.antMatchers("/login", "/blogs/listAllBlogs", "/blogs/listBloggerInfo", "/theme/listAll").permitAll().anyRequest().authenticated().and().formLogin() // 默认 login 登陆路径.failureHandler(failLoginHandler)// 成功处理逻辑
// .defaultSuccessUrl("/success")
// .failureUrl("/error").and().addFilterAfter(tokenFilter, BasicAuthenticationFilter.class);http.csrf().disable();http.cors().disable();}
详细配置思维导图