SSM整合SpringSecurity

  • Post author:
  • Post category:其他




1、Spring Security是什么?

Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。Spring Security的实现与RBAC模型密不可分。



2、RBAC是什么?

RBAC字面上的意思是基于角色的访问控制(Role-Based Access Control)。在RBAC模型中,用户具有角色,角色具有权限,而资源需要相应的权限或者角色才被允许访问。



3、整合Spring Security



i、添加依赖

给pom.xml文件添加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>



ii、添加配置

在web.xml中添加SpringSecurity的过滤器

<!-- SpringSecurity 的 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>



iii、添加配置类

在项目中创建Spring Security的配置类CrowdfundingSecurityConfig,该类继承自WebSecurityConfigurerAdapter父类,代码如下:

@Configuration // 表示当前类为配置类
@EnableWebSecurity // 启用Web安全
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启基于方法的安全认证机制,也就是说在controller层启用注解机制的安全确认
public class CrowdfundingSecurityConfig extends WebSecurityConfigurerAdapter {

    private final CrowdUserDetailService userDetailService;

	// 采用自定义的userDetailService,以便从数据库中获取账户信息
    public CrowdfundingSecurityConfig(CrowdUserDetailService userDetailService) {
        this.userDetailService = userDetailService;
    }

	// 加盐加密,将该对象加入IoC容器
    @Bean
    public BCryptPasswordEncoder getPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailService).passwordEncoder(getPasswordEncoder());
    }

	// 权限配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	// 设置静态文件可以无权限访问,设置管理员页面需要用户管理角色才可访问
    	// 以及设置登录页,登录处理,登录失败,登录成功页,登出页
        http.authorizeRequests()
                .antMatchers("/bootstrap/**","/crowd/**","/css/**","/fonts/**","/img/**","/jquery/**"," /layer/**","/script/**","/ztree/**")
                .permitAll()
                .antMatchers("/admin/get/page.html") 
                .hasRole("用户管理")
                .anyRequest()
                .authenticated()
                .and()
                .exceptionHandling()
                .accessDeniedHandler(new AccessDeniedHandler() {
                    @Override
                    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
                        httpServletRequest.setAttribute(CrowdConstant.ATTR_NAME_EXCEPTION, new Exception(CrowdConstant.MESSAGE_ACCESS_DENIED));
                        httpServletRequest.getRequestDispatcher("/WEB-INF/system-error.jsp").forward(httpServletRequest,httpServletResponse);
                    }
                })
                .and()
                .formLogin()
                .loginPage("/admin/to/login/page.html")
                .permitAll()
                .loginProcessingUrl("/security/do/login.html")
                .usernameParameter("loginAcct")
                .passwordParameter("userPswd")
                .defaultSuccessUrl("/admin/to/main/page.html")
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/security/do/logout.html")
                .logoutSuccessUrl("/admin/to/login/page.html")
                .and()
                .csrf()
                .disable();//禁用CSRF功能,实际开发中不要禁用
    }
}

该配置类放在了SpringMVC的扫描目录下,因此只有当SpringMVC的IoC容器启动后,才能找到Spring Security的过滤器。

以下为自定的UserDetailsService,为的是从数据库中获取账户信息:

@Component
public class CrowdUserDetailService implements UserDetailsService {

    private final AdminService adminService;
    private final RoleService roleService;
    private final AuthService authService;

    public CrowdUserDetailService(AdminService adminService, RoleService roleService, AuthService authService) {
        this.adminService = adminService;
        this.roleService = roleService;
        this.authService = authService;
    }

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    	// 获取账户名为s的管理员账户信息
        Admin admin = adminService.getAdmin(new Admin(s, null)).get(0);
        // 获取分配给该账户的角色列表
        List<Role> assignedRoleList = roleService.getAssignedRole(admin.getId());
        // 获取分配给该账户的权限
        List<String> authNameList = authService.getAssignedAuthNameByAdminId(admin.getId());
        // 构造GrantedAuthority的集合
        List<GrantedAuthority> authorities = new ArrayList<>();
        // 根据Spring Security的定义,角色前面要加“ROLE_”
        for (Role role : assignedRoleList) {
            String roleName = "ROLE_" + role.getName();
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(roleName);
            authorities.add(simpleGrantedAuthority);
        }
        for (String auth : authNameList) {
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(auth);
            authorities.add(simpleGrantedAuthority);
        }
        // 返回账户信息和GrantedAuthority集合
        return new SecurityAdmin(admin, authorities);
    }

}



iv、配置资源权限



a、配置页面访问权限

在配置类的configure(HttpSecurity http)方法中可以进行页面访问权限配置。如下代码,设置了静态文件可以无权限访问,设置管理员页面需要用户管理角色才可访问。

http.authorizeRequests()
                .antMatchers("/bootstrap/**","/crowd/**","/css/**","/fonts/**","/img/**","/jquery/**"," /layer/**","/script/**","/ztree/**")
                .permitAll()
                .antMatchers("/admin/get/page.html")
                .hasRole("用户管理")



b、配置方法访问权限

@PreAuthorize表示在执行该方法前,需要判断当前用户是否具有相应角色或相应权限。如下代码,在执行save方法前,用户需要拥有”user:add”权限。

@PreAuthorize("hasAuthority('user:add')")
@RequestMapping("/do/add.html")
public String save(Admin admin){
	······
}



c、配置页面元素访问权限

在网页上可以使用标签 security:authorize 对元素进行权限控制。如下代码,只有当用户具有角色“用户管理”时,才能在页面上看到标签内容。

<security:authorize access="hasRole('用户管理')">
	<li style="height:30px;">
		<a href="/admin/get/page.html"><i class="glyphicon glyphicon-user"></i> 用户维护</a>
	</li>
</security:authorize>



4、注意事项

在开发过程中遇到过一个BUG,程序报了 springSecurityFilterChain 找不到的错,那是因为我的程序中有两个IoC容器,分别是 Spring 和 Spring MVC 的IoC容器,在程序运行的时候,是先加载的Spring IoC,后加载的Spring MVC IoC,而 springSecurityFilterChain 这个Bean是在Spring MVC IoC里面的,所以在程序运行一开始,会找不到 springSecurityFilterChain,然后就报错了,解决方案就是将两个IoC容器合二为一个。



版权声明:本文为Stone__Fly原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。