SpringSecurity概念及整合ssm框架的示例详解

基本概念

Spring中提供安全认证服务的框架,认证:验证用户密码是否正确的过程,授权:对用户能访问的资源进行控制

SpringSecurity概念及整合ssm框架的示例详解_第1张图片

用户登录系统时我们协助 SpringSecurity 把用户对应的角色、权限组装好,同时把各个资源所要求的权限信息设定好,剩下的“登录验证”、“权限验证”等等工作都交给SpringSecurity。

权限管理过程中的相关概念

主体

英文单词:principal

使用系统的用户或设备或从其他系统远程登录的用户等等。简单说就是谁使用系统谁就是主体。

认证

英文单词:authentication

权限管理系统确认一个主体的身份,允许主体进入系统。简单说就是“主体”证明自己是谁。笼统的认为就是以前所做的登录操作。

授权

英文单词:authorization

将操作系统的“权力”“授予”“主体”,这样主体就具备了操作系统中特定功能的能力。

所以简单来说,授权就是给用户分配权限。

SpringSecurity概念及整合ssm框架的示例详解_第2张图片

使用

pom文件中加入spring security的依赖



org.springframework.security
spring-security-web
4.2.10.RELEASE



org.springframework.security
spring-security-config
4.2.10.RELEASE



org.springframework.security
spring-security-taglibs
4.2.10.RELEASE

web.xml加入SpringSecurity控制权限的Filte

    
        springSecurityFilterChain
        org.springframework.web.filter.DelegatingFilterProxy
    
    
        springSecurityFilterChain
        /*
    

加入配置类

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> getPageInfo(
            @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize", defaultValue = "4") Integer pageSize,
            @RequestParam(value = "keyword", defaultValue = "") String keyword
    ) {
        // 获取页面数据
        PageInfo 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> saveList(@RequestBody List 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 roles = roleService.getAssignedRole(adminId);
        // 4、根据adminId查询权限名字信息
        List auths = authService.getAssignedAuthNameByAdminId(adminId);
        // 5、创建集合对象来存储GrantedAuthority
        ArrayList 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对象)--%>

标签库控制

<%--需要导入taglib--%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %>

     ……

access属性可以传入权限控制相关的表达式。

/>

### 标签库控制

```html
<%--需要导入taglib--%>
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="security" %>

     ……

access属性可以传入权限控制相关的表达式。

到此这篇关于SpringSecurity概念以及整合ssm框架的文章就介绍到这了,更多相关SpringSecurity整合ssm框架内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(SpringSecurity概念及整合ssm框架的示例详解)