SpringSecurity概念及整合ssm框架的示例详解
作者:冬竹️
基本概念
Spring中提供安全认证服务的框架,认证:验证用户密码是否正确的过程,授权:对用户能访问的资源进行控制
用户登录系统时我们协助 SpringSecurity 把用户对应的角色、权限组装好,同时把各个资源所要求的权限信息设定好,剩下的“登录验证”、“权限验证”等等工作都交给SpringSecurity。
权限管理过程中的相关概念
主体
英文单词:principal
使用系统的用户或设备或从其他系统远程登录的用户等等。简单说就是谁使用系统谁就是主体。
认证
英文单词:authentication
权限管理系统确认一个主体的身份,允许主体进入系统。简单说就是“主体”证明自己是谁。笼统的认为就是以前所做的登录操作。
授权
英文单词:authorization
将操作系统的“权力”“授予”“主体”,这样主体就具备了操作系统中特定功能的能力。
所以简单来说,授权就是给用户分配权限。
使用
pom文件中加入spring security的依赖
<!-- SpringSecurity 对 Web 应用进行权限管理 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.2.10.RELEASE</version> </dependency> <!-- SpringSecurity 配置 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.2.10.RELEASE</version> </dependency> <!-- SpringSecurity 标签库 --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-taglibs</artifactId> <version>4.2.10.RELEASE</version> </dependency>
web.xml加入SpringSecurity控制权限的Filte
<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>
加入配置类
package com.atguigu.crowd.mvc.config; import com.atguigu.crowd.constant.CrowdConstant; 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.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.access.AccessDeniedHandler; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Configuration// 表示当前类是一个配置类 @EnableWebSecurity// 启用web环境下权限控制 // prePostEnabled = true的作用:保证@PreAuthorize、@PreAuthorize、@PreFilter、@PostFilter生效 @EnableGlobalMethodSecurity(prePostEnabled = true)// 启用全局方法权限控制 public class WebApplicationConfig extends WebSecurityConfigurerAdapter { @Autowired CrowdUserDetailsService crowdUserDetailsService; @Autowired BCryptPasswordEncoder passwordEncoder; @Override protected void configure(HttpSecurity security) throws Exception { security .authorizeRequests() .antMatchers("/admin/to/login/page.html") .permitAll()// 允许无条件访问登录请求 .antMatchers("/bootstrap/**", "/crowd/**", "/css/**", "/fonts/**", "/img/**", "/jquery/**", "/layer/**", "/script/**", "/ztree/**") .permitAll()// 允许无条件访问静态文件 .antMatchers("/admin/get/page.html") .hasAuthority("user:get") // 拥有user:get权限才可以访问用户维护 .antMatchers("/role/to/role/page.html") .hasRole("经理")// 拥有经理角色才可以访问角色维护 .antMatchers("/admin/get/page.html") .access("(hasAnyRole('经理')) and hasAuthority('user:get')") .anyRequest() .authenticated()// 其他任何资源都要登录才可以访问 .and() .exceptionHandling() .accessDeniedHandler(new AccessDeniedHandler() { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { request.setAttribute("exception", new Exception(CrowdConstant.MESSAGE_ACCESS_DENIED)); request.getRequestDispatcher("/WEB-INF/error/system_error.jsp").forward(request, response); } })// 出现异常的处理方法 .and() .csrf() .disable()// 禁用跨站请求伪造功能 .formLogin()// 开启表单登录功能 .loginPage("/admin/to/login/page.html")// 设置默认的登录页面 .loginProcessingUrl("/security/do/login.html")// 处理登录请求的地址 .defaultSuccessUrl("/admin/to/admin-main/page.html")// 登录成功后要前往的地址 .usernameParameter("loginAcct")// 账号的请求参数名 .passwordParameter("userPswd")// 密码的请求参数名 .and() .logout() .logoutUrl("/security/do/logout.html")// 退出登录访问的地址 .logoutSuccessUrl("/admin/to/login/page.html")// 退出页面成功要去的地址 ; } @Override protected void configure(AuthenticationManagerBuilder builder) throws Exception { // builder // .inMemoryAuthentication()// 开启内存认证 // .withUser("tom")// 设置账号 // .password("123123")// 设置密码 // .roles("ADMIN")// 设置角色 // ; // 使用基于数据库的认证 builder.userDetailsService(crowdUserDetailsService).passwordEncoder(passwordEncoder); } }
注解@PreAuthorize规定角色权限
需要在SpringSecurity中标注
@EnableGlobalMethodSecurity(prePostEnabled = true)
/** * 根据关键字查询分页信息 * * @param pageNum 当前页码 * @param pageSize 每页显示条数 * @param keyword 关键字 * @return 分页信息 */ @PreAuthorize("hasAuthority('role:get') or hasAnyRole('经理')")// 需要有role:get权限才可以访问 @ResponseBody @GetMapping("/role/get/page/info.json") public ResultEntity<PageInfo<Role>> getPageInfo( @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum, @RequestParam(value = "pageSize", defaultValue = "4") Integer pageSize, @RequestParam(value = "keyword", defaultValue = "") String keyword ) { // 获取页面数据 PageInfo<Role> pageInfo = roleService.getRoleByKeyword(pageNum, pageSize, keyword); // 如果出现异常,dispatcherServlet会进行处理 return ResultEntity.successWithData(pageInfo); }
@PostAuthorize
先执行方法然后根据方法返回值判断是否具备权限。
例如:查询一个 Admin 对象,在@PostAuthorize 注解中和当前登录的 Admin 对象进行比较,如果不一致,则判断为不能访问。实现“只能查自己”效果。
@PostAuthorize("returnObject.data.loginAcct == principal.username")
使用 returnObject 获取到方法返回值,使用 principal 获取到当前登录用户的主体对象。
通过故意写错表达式,然后从异常信息中发现表达式访问的是下面这个类的属性:
org.springframework.security.access.expression.method.MethodSecurityExpressionRoot
@PreFilter
在方法执行前对传入的参数进行过滤。只能对集合类型的数据进行过滤。
@PreFilter(value="filterObject%2==0") @ResponseBody @RequestMapping("/admin/test/pre/filter") public ResultEntity<List<Integer>> saveList(@RequestBody List<Integer> valueList) { return ResultEntity.successWithData(valueList); }
@PostFilter
在方法执行后对方法返回值进行过滤。只能对集合类型的数据进行过滤。
CrowdUserDetailsService
其实返回的就是SpringSecurity的User对象,只是做了一层封装。
package com.atguigu.crowd.mvc.config; import com.atguigu.crowd.entity.Admin; import com.atguigu.crowd.entity.Role; import com.atguigu.crowd.service.api.AdminService; import com.atguigu.crowd.service.api.AuthService; import com.atguigu.crowd.service.api.RoleService; 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.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Component public class CrowdUserDetailsService implements UserDetailsService { @Autowired private AdminService adminService; @Autowired private RoleService roleService; @Autowired private AuthService authService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 1、根据账号名称查找Admin对象 Admin admin = adminService.getAdminByLoginAcct(username); // 2、获取adminId Integer adminId = admin.getId(); // 3、根据adminId查询角色信息 List<Role> roles = roleService.getAssignedRole(adminId); // 4、根据adminId查询权限名字信息 List<String> auths = authService.getAssignedAuthNameByAdminId(adminId); // 5、创建集合对象来存储GrantedAuthority ArrayList<GrantedAuthority> authorities = new ArrayList<>(); // 6、遍历存入角色消息 for (int i = 0; i < roles.size(); i++) { // 需要加前缀,因为SpringSecurity就是通过ROLE_来区分是角色还是权限 String roleName = "ROLE_" + roles.get(i).getName(); SimpleGrantedAuthority authority = new SimpleGrantedAuthority(roleName); authorities.add(authority); } // 7、遍历存入权限信息 for (int i = 0; i < auths.size(); i++) { String authName = auths.get(i); SimpleGrantedAuthority authority = new SimpleGrantedAuthority(authName); authorities.add(authority); } // 8、封装到SecurityAdmin对象中,它继承了SpringSecurity的User类 SecurityAdmin securityAdmin = new SecurityAdmin(admin, authorities); return securityAdmin; } }
BCryptPasswordEncoder
它是SpringSecurity自带的密码加密与验证的类。
页面元素控制
取出当前登录对象
<%--需要导入taglib--%> <%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %> <%--principal 是我们自己封装的 SecurityAdmin 对象(返回的SpringSecurity的User对象)--%> <security:authentication property="principal.originalAdmin.userName"/>
标签库控制
<%--需要导入taglib--%> <%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %> <security:authorize access="hasRole('经理')"> <!-- 开始和结束标签之间是要进行权限控制的部分。检测当前用户是否有权限,有权限 就显示这里的内容,没有权限就不显示。 --> …… </security:authorize>
access属性可以传入权限控制相关的表达式。
### 标签库控制 ```html <%--需要导入taglib--%> <%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %> <security:authorize access="hasRole('经理')"> <!-- 开始和结束标签之间是要进行权限控制的部分。检测当前用户是否有权限,有权限 就显示这里的内容,没有权限就不显示。 --> …… </security:authorize>
access属性可以传入权限控制相关的表达式。
到此这篇关于SpringSecurity概念以及整合ssm框架的文章就介绍到这了,更多相关SpringSecurity整合ssm框架内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!