导入依赖框架
web 框架(spring-boot-starter-web)
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
springSecurity 框架(spring-boot-starter-security)
java
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
导入框架之后、当前应用已经具备验证功能
用户名默认为user、密码为启动窗口打印信息
默认登陆页(存在问题、每次需要记录登录密码)
配置文件配置固定用户名、密码
自定义功能实现(用户信息从数据库获取)
方式一:
导入数据源依赖 mysql\mybatis,配置数据源信息
java<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>
2.直接配置查询 sql (select username,password from s_usr where username = ?)
javapackage 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 { @Autowired private DataSource dataSource; @Override protected 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 = ?"); } // 不进行解密、直接对比 @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); } }
此时用户信息就是去数据库查询的 (用户信息表 创建包含用户密码关键字段即可)
sqlcreate table s_usr ( user_id varchar(36) not null primary 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 用户信息查询接口(内部具体编写查询逻辑 )
sqlpackage 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 { @Autowired private UserDetailsDao userDetailsDao; @Override public 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 加解密工具
java// 不进行解密、直接对比 @Bean public PasswordEncoder passwordEncoder() { return NoOpPasswordEncoder.getInstance(); }
UserDetail 用户信息
javapackage 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; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } public void setUsername(String username) { this.username = username; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
AuthenticationProvider 验证流程
javapackage 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 { @Autowired private UserDetailsService userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Override public 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()); } @Override public boolean supports(Class<?> aClass) { return true; } }
验证组件交给springSecurity (同数据源方式类似)
javapackage 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 { @Autowired private UserAuthorizedServiceImpl userAuthorizedService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(userAuthorizedService); } }
配置其他信息(成功跳转、失败跳转....)
java
// 非页面列表页可以无权限访问外、其他都需要验证
@Override
protected 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();
}