什么是RBAC模型:
概念
权限管理,这是每个软件系统都会涉及到的,而且权限管理的需求本质往往都是一样,不同的角色拥有不同的权限,只要你充当了某个角色,你就拥有了相对应的功能。
RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。
简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。
这样,就构造成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间,一般都是多对多的关系
简介
https://docs.spring.io/spring-security/site/docs/4.2.10.RELEASE/guides/html5/helloworld-xml.html
SpringSecurity融合Spring技术栈,提供JavaEE应 用的整体安全解决方案;
Spring Security为基于Java EE的企业软件应用提供全面的安全服务。
Spring Security只需要少量配置,就能构建一个强大的安全的应用系统。
目前市面上受欢迎的两个安全框架:Apache Shiro、SpringSecurity;
SpringSecurity可以无缝整合Spring应用,具有强大的自动化web安全管控功能。而Shiro是一个轻量级强大的安全框架,可以脱离web应用来提供安全管控,但是对于web的一些定制安全需要手动编写;SpringBoot底层默认整合SpringSecurity作为安全框架,所以我们推荐web应用使用SpringSecurity来控制安全;
概念
认证
authentication:身份验证
“身份验证”是指建立主体(principal)的过程,主体就是他们声称是谁(“主体”通常指用户、设备或在应用程序中可以执行动作的其他系统)。也就是“证明你是谁”
授权
authorization:授权
“授权”是指确定主体(principal)是否被允许执行系统中某个动作的过程。 也就是“你能做什么!”
为了达到“授权”决策(安全框架决定你是否有权限做此事),“身份验证”(authentication)过程已经建立了主体的身份(Principal)
使用方式:
细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器, 并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置。
在原有项目中实现Spring Security权限控制:
1.在parent中添加spring security的依赖
<!-- spring-security依赖包 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring-security.version}</version>
</dependency>
2.在web.xml中配置spring Security的过滤器进行控制
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.填写config配置类
package com.atguigu.atcrowdfunding.config;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDeniedException;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.AccessDeniedHandler;
@Configuration // 把该类当成配置文件
@EnableWebSecurity // 开启SpringSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)//开启细粒度权限
public class AtcrowdfundingSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
// 认证与授权
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
// 配置信息
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 放行的请求
.antMatchers("/static/**", "/welcome.jsp", "/login", "/index").permitAll()
// 剩下的请求必须验证
.anyRequest().authenticated();
// 自定义登录页面
http.formLogin().loginPage("/login")
.usernameParameter("loginacct").
passwordParameter("userpswd")// 登录参数的属性名称
.loginProcessingUrl("/doLogin")// 登录的跳转路径
.defaultSuccessUrl("/main");// 跳转的页面
// 禁用csrf
http.csrf().disable();// 暂时
// //出现异常显示的页面
http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
String header = request.getHeader("X-Requested-With");
if("XMLHttpRequest".equals(header)) {
response.getWriter().print("403");
}else {
request.getRequestDispatcher("/WEB-INF/jsp/error/error403.jsp").forward(request, response);;
}
}
});
}
}
4.实现查询数据库进行用户权限认证:
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
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.Component;
import com.atguigu.atcrowdfunding.bean.TAdmin;
import com.atguigu.atcrowdfunding.bean.TAdminExample;
import com.atguigu.atcrowdfunding.bean.TAdminExample.Criteria;
import com.atguigu.atcrowdfunding.bean.TPermission;
import com.atguigu.atcrowdfunding.bean.TRole;
import com.atguigu.atcrowdfunding.mapper.TAdminMapper;
import com.atguigu.atcrowdfunding.mapper.TPermissionMapper;
import com.atguigu.atcrowdfunding.mapper.TRoleMapper;
//实现查询数据库的用户权限的认证
@Component
public class MyUserDetailsService implements UserDetailsService{
@Autowired
private TAdminMapper tAdminMapper;
@Autowired
private TRoleMapper tRolemapper;
@Autowired
private TPermissionMapper tPermissionMapper;
//查询用户的角色和权限数据
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
TAdminExample example=new TAdminExample();
Criteria criteria = example.createCriteria();
criteria.andUsernameEqualTo(username);
//根据用户名查询用户的信息
List<TAdmin> list = tAdminMapper.selectByExample(example);
TAdmin tAdmin=null;
if(list!=null&&list.size()==1) {
tAdmin=list.get(0);
}
//查询用户的角色
List<TRole> roleList=tRolemapper.queryRoleByAdminId(tAdmin.getId());
List<TPermission>permissionList=tPermissionMapper.queryPermissionByAdminId(tAdmin.getId());
//查询用户的角色对应的权限
//List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_初级程序员","ROLE_中级程序员");
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
for (TRole role : roleList) {
authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));
}
for (TPermission permission : permissionList) {
authorities.add(new SimpleGrantedAuthority(permission.getName()));
}
return new User(tAdmin.getLoginacct(), tAdmin.getUserpswd(), authorities);
}
}
6.对权限控制进行细粒度控制:(添加注解).
@EnableWebSecurity:开启 Spring Security 注解
@EnableGlobalMethodSecurity(prePostEnabled=true):开启全局的细粒度方法级别权限控制功能
@PreAuthorize:方法执行前检查
hasRole是角色,hasAuthority是具体的操作,这两个都可以是多个,细粒度控制可以具体到每一个角色的具体操作步骤。动态的不影响项目代码的逻辑结构。
注意事项:
在使用Springsecurity的细粒度控制时由于Springsecurity是被Spring扫描的,而controller是被SpringMVC扫描的,父不能访问子容器中的内容,所以细粒度注解不能生效,需要在web.xml中更改配置