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进行认证与授权使用
- InvocationSecurityMetadataSourceService
我采用的数据库方式储存权限
二、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>
- web.xml配置Security的Filter拦截所有请求
-
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); } }
- 编写SpringSecurity的配置类
-
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; }
- 加入注解到SpringSecurity的配置类,即上面的AtcrowdfundingSecurityConfig类
推荐阅读
-
Spring Security Crypto 简单实现AES加解密
-
spring-security3(一)配置详解及API扩展(包含ajax返回)
-
spring security xml配置详解(转载)
-
Spring Security自定义数据表完整实现
-
使用security在画面级别控制权限
-
报表传递参数控制数据权限 博客分类: 报表制作展现 报表美化美化报表复杂报表设计统计图数据可视化
-
javaWeb用户权限控制简单实现过程
-
256.Spring Boot+Spring Security: MD5是加密算法吗? 博客分类: 从零开始学Spring Boot Spring Boot
-
spring-security(十七)Filter顺序及简介 博客分类: spring security springsecurity
-
Spring4 Jasypt1.9.2 Integration 博客分类: 數據安全 Security