? ? ? ? 前面的系列文章介绍了基于内存定义用户的方式,其实Spring Security中还提供了基于Jdbc的用户认证 & 授权,再说基于Jdbc的用户认证 & 授权之前,不得不说一下Spring Security中一个非常重要的类UserDetailService,关于UserDetailService,请参考【系列二、Spring Security中的核心类】,这里不再赘述。
????????JdbcUserDetailsManager实现了UserDetailsManager接口,UserDetailsManager继承于UserDetailsService接口,继承结构如下:
通过这个类可以使用Spring Security内置的Jdbc操作数据库。
org/springframework/security/core/userdetails/jdbc/users.ddl
DROP TABLE IF EXISTS `users`;
create table users(
username varchar(50) not null primary key COMMENT '用户名',
password varchar(100) not null COMMENT '密码',
enabled int not null COMMENT '账户是否启用(1:启用、0:禁用)'
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户表' ROW_FORMAT = DYNAMIC;
DROP TABLE IF EXISTS `authorities`;
create table authorities (
username varchar(50) not null COMMENT '用户名',
authority varchar(50) not null COMMENT '权限',
constraint fk_authorities_users foreign key(username) references users(username)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '权限表' ROW_FORMAT = DYNAMIC;
create unique index ix_auth_username on authorities (username,authority);
/**
* @Author : 一叶浮萍归大海
* @Date: 2024/1/11 20:58
* @Description: 测试资源
*/
@RestController
public class HelloController7004 {
/**
* 任何人都可以访问
* @return
*/
@GetMapping("/helloWorld")
public R helloWorld() {
return R.ok().data("Hello World");
}
/**
* 登录后才能访问
* @return
*/
@GetMapping("/sayHi")
public R sayHi() {
return R.ok().data("嗨!");
}
/**
* 需要具有dba角色的人才能访问
* @return
*/
@GetMapping("/dba/helloWorld")
public R dba() {
return R.ok().data("dba Hello World");
}
/**
* 需要具有admin角色的人才能访问
* @return
*/
@GetMapping("/admin/helloWorld")
public R admin() {
return R.ok().data("admin Hello World");
}
}
/**
* @Author : 一叶浮萍归大海
* @Date: 2024/1/11 21:50
* @Description: Spring Security配置类
*/
@Configuration
public class MyWebSecurityConfigurerAdapter7004 extends WebSecurityConfigurerAdapter {
@Resource
private MyAuthenticationSuccessHandler7004 successHandler;
@Resource
private MyAuthenticationFailureHandler7004 failureHandler;
@Resource
private MyLogoutSuccessHandler7004 logoutSuccessHandler;
@Resource
private MyAuthenticationEntryPoint7004 authenticationEntryPoint;
@Resource
private MyAccessDeniedHandler7004 accessDeniedHandler;
@Resource
private DataSource dataSource;
/**
* 密码加密器
* @return
*/
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
/**
* 根据UserDetailsService定义基于Jdbc的用户
* 调用 userExists 方法判断用户是否存在,如果不存在,就创建一个新的用户出来(因为每次项目启动时这段代码都会执行,所以加一个判断,避免重复创建用户)
* @return
*/
@Bean
protected UserDetailsService userDetailsService() {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
manager.setDataSource(dataSource);
if (!manager.userExists("admin")) {
manager.createUser(User.withUsername("admin").password("123456").roles("admin").build());
}
if (!manager.userExists("dba")) {
manager.createUser(User.withUsername("dba").password("123456").roles("dba").build());
}
return manager;
}
/**
* 角色继承
* @return
*/
@Bean
protected RoleHierarchy roleHierarchy() {
RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
roleHierarchy.setHierarchy("ROLE_admin > ROLE_dba");
return roleHierarchy;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/dba/**").hasRole("dba")
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/helloWorld")
.permitAll()
.anyRequest()
.authenticated()
.and()
/**
* 登录成功 & 登录失败回调
*/
.formLogin()
.loginPage("/login")
.successHandler(successHandler)
.failureHandler(failureHandler)
.and()
/**
* 注销登录回调
*/
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler)
.permitAll()
.and()
.csrf()
.disable()
/**
* 未认证 & 权限不足回调
*/
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler);
}
}
? ? ? ? 测试流程同【系列六、Spring Security中的认证 & 授权 & 角色继承???????】,这里不再赘述。