欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Security——权限控制

程序员文章站 2022-05-05 23:13:14
...

一、SpringSecurity-简介

  • 概念
    • Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是保护基于spring的应用程序的实际标准。
    • Spring Security是一个框架,侧重于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring安全性的真正强大之处在于它很容易扩展以满足定制需求
  • 4种使用方式
    • ①全部利用配置文件,将用户、权限、资源(url)硬编码在xml文件中
    • ②用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置
    • ③细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器, 并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置。
    • ④修改springsecurity的源代码,主要是修改InvocationSecurityMetadataSourceService和UserDetailsService两个类。
      • InvocationSecurityMetadataSourceService
        • 将配置文件或数据库中存储的资源(url)提取出来加工成为url和权限列表的Map供Security使用
      • UserDetailsService
        • 提取用户名和权限组成一个完整的(UserDetails)User对象,该对象可以提供用户的详细信息供AuthentationManager进行认证与授权使用

我采用的数据库方式储存权限

Spring Security——权限控制

Spring Security——权限控制

Spring Security——权限控制

二、SpringSecurity-HelloWorld

  • 1、引入SpringSecurity的依赖,pom.xml
    <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-web</artifactId>
         <version>4.2.10.RELEASE</version>
    </dependency>
    <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-config</artifactId>
         <version>4.2.10.RELEASE</version>
    </dependency>
    <!-- 标签库 -->
    <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-taglibs</artifactId>
         <version>4.2.10.RELEASE</version>
    </dependency> 
    
  • 2、 编写SpringSecurity的配置
    • web.xml配置Security的Filter拦截所有请求
      <!-- 权限过滤Filter -->
      <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、控制登录
    • 编写SpringSecurity的配置类
      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.crypto.bcrypt.BCryptPasswordEncoder;
      import org.springframework.security.web.access.AccessDeniedHandler;
      
      @Configuration
      @EnableWebSecurity
      public class AtcrowdfundingSecurityConfig extends WebSecurityConfigurerAdapter {
      
      	@Autowired
      	private UserDetailsService userDetailsService;
      
      	// 认证和授权
      	@Override
      	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      		//new BCryptPasswordEncoder()是对密码的加密算法
      		auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
      	}
      
      	@Override
      	protected void configure(HttpSecurity http) throws Exception {
      		// 设置哪些资源可以被访问
      		http.authorizeRequests()
      		//这些资源可以直接访问
      		.antMatchers("/static/**", "/welcome.jsp", "/login").permitAll()
      		//其他的访问需要认证
      		.anyRequest().authenticated();
      
      		//设置没有登录不能访问的资源跳转到我们自己的登录页(他存在一个默认的很丑的登录页)
      		http.formLogin()
      		.loginPage("/login")//请求到我们自己写的登录界面
      		.usernameParameter("loginacct")//这里填入我们登陆界面的用户名name属性
      		.passwordParameter("userpswd")//密码
      		.loginProcessingUrl("/doLogin")//登录信息验证请求
      		.defaultSuccessUrl("/main");//登录成功后跳转的界面
      		
      		//禁用跨站请求伪造,让测试更简单,实际情况通常不会禁用
      		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);
      					;
      				}
      			}
      		});
      
      		// 退出登录后跳转的请求
      		http.logout().logoutSuccessUrl("/index");
      		http.rememberMe();
      	}		
      }
      
    • 验证登录信息是否正确,如果正确,查出他拥有的所有权限
      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;
      	
      @Component
      public class MyUserDetailsServiceImpl implements UserDetailsService {
      
      	@Autowired
      	private TAdminMapper adminMapper;
      	@Autowired
      	private TRoleMapper roleMapper;
      	@Autowired
      	private TPermissionMapper permissionMapper;
      
      	@Override
      	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
      		// 通过用户名认证
      		TAdminExample example = new TAdminExample();
      		example.createCriteria().andUsernameEqualTo(username);
      		List<TAdmin> admins = adminMapper.selectByExample(example);
      		TAdmin admin = null;
      		if (admins != null && admins.size() != 0) {
      			admin = admins.get(0);
      		}
      		// 认证结束
      		// 查询用户角色
      		int adminId = admin.getId();
      		List<TRole> roles = roleMapper.queryRoleByAdminId(adminId);
      		// 查询用户拥有的权限
      		List<TPermission> permissions = permissionMapper.queryPermissionByAdminId(adminId);
      		// 用户拥有的权限(角色+权限)
      		Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
      		for (TRole role : roles) {
      			authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
      		}
      		for (TPermission permission : permissions) {
      			authorities.add(new SimpleGrantedAuthority(permission.getName()));
      		}
      		return new User(admin.getLoginacct(), admin.getUserpswd(), authorities);
      	}
      
      }
      
  • 4、细粒度权限功能
    • 加入注解到SpringSecurity的配置类,即上面的AtcrowdfundingSecurityConfig类
      //开启细粒度权限功能
      @EnableGlobalMethodSecurity(prePostEnabled = true)
      
    • 可以精确到一个按钮的权限
      • ①是组长身份才能看到“管理组员”按钮
      <sec:authorize access="hasRole('TL - 组长')">
      	<button type="button" class="btn btn-default btn-danger">
      	    <span class="glyphicon glyphicon-question-sign">管理组员</span> 
      	</button>
      </sec:authorize>
      
      Spring Security——权限控制
    • ②不隐藏按钮,而是在点击后告诉用户没有权限
      • 我们将权限控制加到方法上面
      • 如果没有权限会跳转的我们最初配置的SpringSecurity的配置类里面的拒绝访问
      // 用户新增
      @PreAuthorize("hasAuthority('user:add')") 
      @RequestMapping("/admin/doAdd")
      public String addAdmin(TAdmin admin) {
      	adminService.saveAdmin(admin);
      	return "redirect:/admin/index?pageNum=" + Integer.MAX_VALUE;
      }
      
相关标签: Spring Security