权限控制一:Spring Security 安全框架

权限控制

认证 和 授权

  • 认证:系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认证的目的是让系统知道你是谁。
  • 授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能。

Spring Security


快速入门

Maven 坐标

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
</dependency>

web.xml 配置

在 web.xml 中主要配置 SpringMVC 的前端控制器-DispatcherServlet 和用于整合第三方框架的 DelegatingFilterProcy,来整合 Spring Security

<!-- 
      DelegatingFilterProxy 用于整合第三方框架
      整合 Spring Security 的时候,<filter-name> 标签内容必须为:springSecurityFilterChain
      否则会抛出 NoSuchBeanDefinitionException
 -->

<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>

<!--前端控制器-->
<servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring-security.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

spring-security.xml

在 spring-security.xml 中主要配置:拦截规则 和 认证管理器

      <!--http:用于定义相关权限控制 指定哪些资源不需要进行权限校验,可以使用通配符 --> 
      <!--配置可匿名访问的资源-->
<security:http security="none" pattern="/pages/a.html" /> 
      <!--使用指定的登陆页面 如果不指定,spring会使用自带的登陆页面-->
<security:http security="none" pattern="login.html" /> 
<security:http security="none" pattern="/pages/**"></security:http>
      <!--
      security:http:用于定义相关权限控制 
      auto-config:是否自动配置 设置为true时框架会提供默认的一些配置,例如提供默认的登录页面、登出 处理等 设置为false时需要显示提供登录表单配置,否则会报错
      use-expressions:用于指定intercept-url中的access属性是否使用表达式 
      -->
<security:http auto-config="true" use-expressions="true"> 

      <!--
      intercept-url:定义一个拦截规则 
      pattern:对哪些url进行权限控制 
      access:在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的角色列表,请求的用户只需拥有其中的一个角色就能成功访问对应的URL 
      -->
      <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
      
      <!--配置登陆表单-->
        <security:form-login login-page="/login.html"
                             username-parameter="username"
                             password-parameter="password"
                             default-target-url="/index.html"
                             login-processing-url="/login.do"
                             authentication-failure-url="/login.html"/>
        <!--关闭 csrf 过滤器-->
        <security:csrf disabled="true"/>

        <!--登出-->
        <security:logout logout-url="/logout.do" 
                         logout-success-url="/login.html" 
                         invalidate-session="true"/>
        
        <!--放行ifrem-->
        <security:headers>
              <security:frame-options policy="SAMEORIGIN"></security:frame-options>
        </security:headers>
</security:http> 

<!--authentication-manager:认证管理器,用于处理认证操作 -->
<security:authentication-manager> 
      <!--authentication-provider:认证提供者,执行具体的认证逻辑 -->
      <security:authentication-provider> 
      <!--使用指定的 security 类进行认证操作,需要将该类交给 spring 管理
      <security:authentication-provider user-service-ref="springSecurityUserService"> 
      -->
            <!--user-service:用于获取用户信息,提供给authentication-provider进行认证 -->
            <security:user-service> 
                  <!--user:定义用户信息,可以指定用户名、密码、角色,后期可以改为从数据库查询 用户信息 {noop}:表示当前使用的密码为明文 -->
                  <security:user name="admin" password="{noop}admin" authorities="ROLE_ADMIN"></security:user>
          </security:user-service>

          <!--指定密码加密策略,使用 BCryptPasswordEncoder,加密时,需要去掉 {noop} 明文标识-->
          <security:password-encoder ref="passwordEncoder"/>
      </security:authentication-provider>
</security:authentication-manager>

<!--开启security注解控制,用于使用注解进行 细颗粒度 控制,例:@PreAuthorize("hasRole('ROLE_ADMIN')")-->
<security:global-method-security pre-post-annotations="enabled" />

<!--配置指定的认证操作类-->
<bean id="springSecurityUserService" class="com.xxx.service.SpringSecurityUserService" />

配置多种校验规则

在注解控制访问权限时,@PreAuthorize("hasRole('ROLE_ADMIN')") 中的校验规则也为以下几种

<!--只要认证通过就可以访问--> 
<security:intercept-url pattern="/index.jsp" access="isAuthenticated()" /> 
<security:intercept-url pattern="/a.html" access="isAuthenticated()" /> 

<!--拥有add权限就可以访问b.html页面--> 
<security:intercept-url pattern="/b.html" access="hasAuthority('add')" /> 

<!--拥有ROLE_ADMIN角色就可以访问c.html页面--> 
<security:intercept-url pattern="/c.html" access="hasRole('ROLE_ADMIN')" /> 

<!--拥有ROLE_ADMIN角色就可以访问d.html页面, 注意:此处虽然写的是ADMIN角色,框架会自动加上前缀ROLE_--> 
<security:intercept-url pattern="/d.html" access="hasRole('ADMIN')" />

从数据库查询用户信息

如果我们要从数据库动态查询用户信息,就必须按照spring security框架的要求提供一个实现UserDetailsService接口的实现类,并按照框架的要求进行配置即可。

示例:

@Component
public class SpringSecurityUserService implements UserDetailsService {

    @Reference
    private BCryptPasswordEncoder passwordEncoder
    @Reference
    private UserService userService;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根据用户名查询用户信息
        User user = userService.findByUserName(username);

        if (user==null){
            return null;
        }
        List<GrantedAuthority> list = new ArrayList<>();
        Set<Role> roles = user.getRoles();
        for (Role role : roles) {
            /*授予角色*/
            list.add(new SimpleGrantedAuthority(role.getKeyword()));
            Set<Permission> permissions = role.getPermissions();
            for (Permission permission : permissions) {
                //授予权限
                list.add(new SimpleGrantedAuthority(permission.getKeyword()));
            }
        }

        String uname = user.getUsername();
        String password = user.getPassword();
        //返回值为 spring 提供UserDetails接口的实现类 User 类,封装用户名、密码、权限信息集合等
        return new org.springframework.security.core.userdetails.User(uname, password,list);
    }
}
posted @ 2020-10-17 21:35  德华。  阅读(412)  评论(0编辑  收藏  举报