Java中的通用权限管理设计(推荐)
简介
在Java应用程序开发过程中,通用权限管理设计可以有效地管理系统内不同用户的权限,做到安全可靠地管理用户访问数据的安全性和可靠性,避免了系统访问被恶意用户攻击,数据泄露和其他相关问题的出现。
设计
本文推荐一种常见的通用权限管理设计方案,使用RBAC(Role Based Access Control)模型,该模型通过将用户的角色和权限组织成组和子组,使得用户所拥有的所有角色都能够赋予他相应的访问权限。并在访问数据时,针对用户的权限进行数据过滤,保障了数据的安全性。
设计思路
- 用户(User):指系统内所有的用户。
- 角色(Role):指是系统内所有可能具有的用户角色,如:管理员、普通用户等。
- 权限(Permission):系统内所有可以进行操作的权限集合。
- 资源(Resource):代表被控制的对象,可以是系统内的任何对象或操作,如:一个文件、一个应用、一张表等。
- 当用户在系统中进行某个操作时,首先会向系统发起申请,系统根据该用户所拥有的角色和权限集合,判断是否具有该操作的访问权限。如果用户拥有访问权限,则可以进行该操作;如果用户没有访问权限,则返回访问失败。
设计实现
在Java程序开发中,可以使用Spring Security框架进行通用权限管理的实现, 其中,Spring Security的核心在于将安全拦截器链绑定到Spring应用程序上,并使用适当的管理器向拦截器链提供身份验证和权限控制信息。
1. 引入Maven依赖
在项目的pom.xml文件中添加Spring Security相关的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>4.2.3.RELEASE</version>
</dependency>
</dependencies>
2. 配置Spring Security
在工程中创建 Spring Security 的配置类,继承 WebSecurityConfigurerAdapter
类,并覆盖其中的几个方法:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsServiceImpl;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 忽略 /login 接口的 CSRF 验证
http.csrf().ignoringAntMatchers("/login");
http.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
.antMatchers("/user").hasAnyRole("ADMIN", "USER")
.anyRequest().permitAll();
// 配置登录页面和登录接口
http.formLogin()
.loginPage("/login").defaultSuccessURL("/")
.failureUrl("/login?error").permitAll();
http.logout().logoutSuccessUrl("/login?logout");
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/images/**");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsServiceImpl);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
3. 创建授权服务
在工程中定义 UserDetailsServiceImpl
类,实现 UserDetailsService 接口:
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Autowired
private RoleRepository roleRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (null == user) {
throw new UserNotFoundException("用户不存在");
}
Collection<GrantedAuthority> grantedAuthorities = new HashSet<>();
List<Role> roles = roleRepository.findByUserId(user.getId());
for (Role role : roles) {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}
4. 数据库表结构设计
设计系统中对应的用户、角色和权限表,并通过表与表之间的关联来实现权限管控和角色与权限的逻辑关系。
CREATE TABLE `t_user` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(100) NOT NULL COMMENT '登录名',
`password` varchar(256) NOT NULL COMMENT '密码',
`email` varchar(100) NOT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
CREATE TABLE `t_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '角色名称',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
PRIMARY KEY (`id`),
KEY `idx_user_role` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
CREATE TABLE `t_permission` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`code` varchar(50) NOT NULL COMMENT '权限编码',
`name` varchar(50) NOT NULL COMMENT '权限名称',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限表';
CREATE TABLE `t_role_permission` (
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
`permission_id` bigint(20) NOT NULL COMMENT '权限ID',
PRIMARY KEY (`role_id`, `permission_id`),
KEY `idx_ROLE_ID` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色权限关联表';
示例
示例1: 演示用户角色授权
在上面的代码示例中,我们定义了 RoleRepository
接口用于操作角色表,定义 PermissionRepository
接口用于操作权限表。下面展示如何定义这两个接口。其中,Role
对应角色表,Permission
对应权限表。
@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
List<Role> findByUserId(Long userId);
}
@Repository
public interface PermissionRepository extends JpaRepository<Permission, Long> {
}
在完成实现以上的接口之后,可以修改 UserDetailsServiceImpl
的实现方式,在其中加入角色权限的赋值代码。示例代码如下:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (null == user) {
throw new UserNotFoundException("用户不存在");
}
Collection<GrantedAuthority> grantedAuthorities = new HashSet<>();
List<Role> roles = roleRepository.findByUserId(user.getId());
for (Role role : roles) {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
List<Permission> permissions = permissionRepository.findByRoleId(role.getId());
for (Permission permission : permissions) {
grantedAuthorities.add(new SimpleGrantedAuthority(permission.getCode()));
}
}
return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
在以上代码完成之后,可以在代码中分配角色和权限实现访问控制。具体代码示例如下:
// 定义角色列表
List<Role> roles = new ArrayList<>();
Role role = new Role();
role.setName("ADMIN");
role.setUserId(user.getId());
roles.add(role);
// 保存角色
List<Role> savedRoles = roleRepository.saveAll(roles);
// 定义用户权限列表
List<Permission> permissions = new ArrayList<>();
Permission permission = new Permission();
permission.setCode("USER_QUERY");
permission.setName("用户查询");
permissions.add(permission);
// 将权限赋给角色
List<RolePermission> rolePermissions = new ArrayList<>();
for (Role savedRole : savedRoles) {
for (Permission savedPermission : savedPermissions) {
RolePermission rolePermission = new RolePermission();
rolePermission.setPermissionId(savedPermission.getId());
rolePermission.setRoleId(savedRole.getId());
rolePermissions.add(rolePermission);
}
}
rolePermissionRepository.saveAll(rolePermissions);
// 查询分配的权限
List<Role> userRoles = roleRepository.findByUserId(user.getId());
for (Role userRole : userRoles) {
List<Permission> userPermissions = permissionRepository.findByRoleId(userRole.getId());
for (Permission permission : userPermissions) {
System.out.println(permission);
}
}
示例2: 演示数据过滤
在Spring Security应用程序中,通常可以使用数据过滤技术实现访问控制,以防止用户访问未授权的数据。例如,在一个在线银行系统中,某个用户只能访问自己名下的账户,而不能访问其他用户的账户。下面是一个搭配Spring Data JPA的简单示例:
(1)定义 JPA 查询接口
public interface UserAccountRepositoryCustom {
List<UserAccount> findByUser(User user);
}
(2)实现 JPA 查询接口
@Component
public class UserAccountRepositoryImpl implements UserAccountRepositoryCustom {
@Autowired
UserAccountRepository userAccountRepository;
@Override
public List<UserAccount> findByUser(User user) {
final QUserAccount qUserAccount = QUserAccount.userAccount;
return new JPAQuery<>(entityManager)
.from(qUserAccount)
.where(qUserAccount.user.eq(user))
.fetch();
}
}
在以上代码中,QUserAccount
表示JPA查询实体,qUserAccount.user
表示其中的用户字段。
(3)在Service中使用
@Service
@Transactional(readOnly = true)
public class UserAccountServiceImpl implements UserAccountService {
@Autowired
UserAccountRepository userAccountRepository;
@Autowired
UserAccountRepositoryCustom userAccountRepositoryCustom;
@Override
public List<UserAccount> findAll() {
User user = getLoginUser();
return userAccountRepositoryCustom.findByUser(user);
}
}
在以上代码中, getLoginUser()
方法获取当前登录用户信息,通过调用 userAccountRepositoryCustom.findByUser(user)
方法获取当前登录用户账户信息,实现了数据过滤的功能。
小结
本文介绍了一种通用权限管理设计方案,使用RBAC(Role Based Access Control)模型,通过将用户的角色和权限组织成组和子组,实现了对用户权限的控制,并在访问数据时,通过数据过滤实现了对用户数据权限的管控。同时,还给出了在Spring Security框架下实现通用权限管理的实现方式,并提供了代码示例和完整的表结构设计。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java中的通用权限管理设计(推荐) - Python技术站