Spring Security——权限控制

一、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进行认证与授权使用

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

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

二、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>
      
      在这里插入图片描述
    • ②不隐藏按钮,而是在点击后告诉用户没有权限
      • 我们将权限控制加到方法上面
      • 如果没有权限会跳转的我们最初配置的SpringSecurity的配置类里面的拒绝访问
      // 用户新增
      @PreAuthorize("hasAuthority('user:add')") 
      @RequestMapping("/admin/doAdd")
      public String addAdmin(TAdmin admin) {
      	adminService.saveAdmin(admin);
      	return "redirect:/admin/index?pageNum=" + Integer.MAX_VALUE;
      }
      
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值