Spring Security 简介

   Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了
Spring IoC,DI(控制反转 Inversion of Control ,DI:Dependency Injection 依赖注入)和 AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

1.引入依赖

在spring依赖引入的基础上,引入spring Security依赖,版本可以使用spring的版本

<!--
     spring Security/身份验证 
    -->
    <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
    </dependency>
    <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>

    </dependency>

2.配置web.xml文件

  1)添加加载Security配置的监听器,
  2)注册安全认证的过滤器链
    这些过滤器实际是在spring容器中管理,这里只是代理注册给web容器

<!-- spring Security 安全认证 监听器,读取配置文件,创建security容器 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/spring-security.xml</param-value>
    </context-param>


    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>



    <!-- 
        spring Security 安全认证 监听器,过滤器链在web中注册 
       这些过滤器实际是在spring容器中管理,这里只是代理注册给web容器
    -->
    <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>

3.添加配置文件 spring-security.xml

使用静态用户(死数据)

<?xml version="1.0" encoding="UTF-8"?>
<bean:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:bean="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.1.xsd">

    <!--
    1、设置放行资源,如登录注册页面,静态资源css、js等等
        security="none" 设置此资源不被拦截.
    -->
    <http pattern="/login.html" security="none"></http>
    <http pattern="/loginerror.html" security="none"></http>
    <http pattern="/css/**" security="none"></http>
    <http pattern="/img/**" security="none"></http>
    <http pattern="/js/**" security="none"></http>
    <http pattern="/plugins/**" security="none"></http>

    <http>
        <!-- 2、拦截所有(除放行资源外) -->
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <!-- 
            3、登录表单设置

            1)login-page:指定登录页面;
            2)login-processing-url:指定登录请求路径;

            3)default-target-url:指定了成功进行身份验证和授权后默认呈现给用户的页面;
            4)always-use-default-target:指定了是否在身份验证通过后总是跳转到; 
                                       default-target-url 属性指定的 URL。

            5)authentication-failure-url:指定了身份验证失败时跳转到的页面;                           

         -->

        <form-login login-page="/login.html" 
                    login-processing-url="/login"
                    always-use-default-target="true" 
                    default-target-url="/admin/index.html"
                    authentication-failure-url="/loginerror.html"

                     />
        <!--   4、注销设置
                  1)logout-url:指定注销的url;
                  2)logout-success-url:注销成功后登录返回的页面。
        -->         
        <logout logout-url="/logout" logout-success-url="/login.html"/>          
        <!-- 
            5、跨站请求设置(我们这里关闭)
               1)csrf disabled="true" 关闭 csrf ,如果不加会出现错误

               2)CSRF(Cross-site request forgery):跨站请求伪造,
                 也被称为“One Click Attack”或者 SessionRiding,
                 通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。
         -->            
        <csrf disabled="true" />

        <!-- 6、iframe 框架结构展示 -->
        <headers>
            <frame-options policy="SAMEORIGIN" />
        </headers>
    </http>
     <!-- 
             认证管理器
             1)我们这里设置一个默认用户
      -->
    <authentication-manager>
        <authentication-provider>
            <user-service>
                <user authorities="ROLE_USER" name="admin" password="123456" />
            </user-service>
        </authentication-provider>
    </authentication-manager>
</bean:beans>

错误一、未关闭跨域请求,csrf disabled=”true” 关闭 csrf ,如果不加会出现错误

Spring Security集成saml2_Spring Security


错误二,未放行登录页面,如果你没有设置登录页 security=”none” ,将会出现以下错误

Spring Security集成saml2_java_02

简单的登录页面

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>登陆</title>
</head>
<body>
        <form action='/login' method='POST'>
            <table>
                <tr>
                    <td>用户名:</td>
                    <td><input type='text' name='username' value=''></td>
                </tr>
                <tr>
                    <td>密码:</td>
                    <td><input type='password' name='password' /></td>
                </tr>
                <tr>
                    <td colspan='2'><input name="submit" type="submit"
                    value=" 登陆 " /></td>
                </tr>
            </table>
        </form>
</body>
</html>

4、数据库动态校验用户

用户认证类

package com.it.manager.service;

import java.util.ArrayList;
import java.util.List;

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 com.it.manager.service.SellerService;
import com.it.pojo.TbSeller;

public class userDetailServiceImpl implements UserDetailsService {

    private SellerService sellerService;

    public SellerService getSellerService() {
        return sellerService;
    }

    public void setSellerService(SellerService sellerService) {
        this.sellerService = sellerService;
    }

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
        //这里设置一个默认权限,也可以通过数据库查询出用户访问权限进行设置
        grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));

        // 调用sellerService查询用户
        TbSeller seller = sellerService.findOne(username);
        if (seller != null && seller.getPassword() != null) {
            //查询返回一个Security框架规定的用户对象,并将用户帐号,密码及权限信息以构造方式传入
            return new User(username, seller.getPassword(), grantedAuths);
        } else {
            return null;
        }

    }

}

在SpringSecurity.xml中设置:
1)注册自定义认证类,并注入到认证管理器中
2)设置加密方式
BCrypt 加密算法
  用户表的密码通常使用 MD5 等不可逆算法加密后存储,为防止彩虹表破解更会先使用一个特定的字符串(如域名)加密,然后再使用一个随机的 salt(盐值)加密。 特定字符
串是程序代码中固定的,salt 是每个密码单独随机,一般给用户表加一个字段单独存储,比较麻烦。 BCrypt 算法将 salt 随机并混入最终加密后的密码,验证时也无需单独提供之前的
salt,从而无需单独处理 salt 问题。

<?xml version="1.0" encoding="UTF-8"?>
<bean:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:bean="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.1.xsd
http://code.alibabatech.com/schema/dubbo 
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
">
    <!--
    1、设置放行资源,如登录注册页面,静态资源css、js等等
        security="none" 设置此资源不被拦截.
    -->
    <http pattern="/login.html" security="none"></http>
    <http pattern="/loginerror.html" security="none"></http>
    <http pattern="/css/**" security="none"></http>
    <http pattern="/img/**" security="none"></http>
    <http pattern="/js/**" security="none"></http>
    <http pattern="/plugins/**" security="none"></http>
    <http pattern="/seller/insert" security="none"></http>
    <http pattern="/shoplogin.html" security="none"></http>
    <http pattern="/register.html" security="none"></http>
    <http>
        <!-- 2、拦截所有(除放行资源外) -->
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        <!-- 
            3、登录表单设置

            1)login-page:指定登录页面;
            2)login-processing-url:指定登录请求路径;

            3)default-target-url:指定了成功进行身份验证和授权后默认呈现给用户的页面;
            4)always-use-default-target:指定了是否在身份验证通过后总是跳转到; 
                                       default-target-url 属性指定的 URL。

            5)authentication-failure-url:指定了身份验证失败时跳转到的页面;                           

         -->
        <form-login 
            login-page="/shoplogin.html"
            login-processing-url="/login" 
            always-use-default-target="true"
            default-target-url="/admin/index.html" 
            authentication-failure-url="/loginerror.html" />
        <!--   4、注销设置
                  1)logout-url:指定注销的url;
                  2)logout-success-url:注销成功后登录返回的页面。
        -->        
        <logout logout-url="/logout" logout-success-url="/login.html" />
        <!-- 
            5、跨站请求设置(我们这里关闭)
               1)csrf disabled="true" 关闭 csrf ,如果不加会出现错误

               2)CSRF(Cross-site request forgery):跨站请求伪造,
                 也被称为“One Click Attack”或者 SessionRiding,
                 通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。
         -->      
        <csrf disabled="true" />
        <!-- 6、iframe 框架结构展示 -->
        <headers>
            <frame-options policy="SAMEORIGIN" />
        </headers>
    </http>

    <!-- 
            二、 认证管理器
             1、引用userDetailService作为用户登录验证的服务类
             2、设置密码加密方式
      -->
    <authentication-manager alias="authenticationManager">
        <!-- 注入自定义认证类对象 -->
        <authentication-provider user-service-ref='userDetailService'>
            <!-- 注入加密算法类 -->
            <password-encoder ref="bcryptEncoder"></password-encoder>
        </authentication-provider>
    </authentication-manager>

    <!-- 2、注册加密算法类,使用BCryptPasswordEncoder加密方式 -->
    <bean:bean id="bcryptEncoder"
        class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />


    <!-- 三、引用dubbo 服务 ,
       用于分布式远程调用服务提供者的注入,
       这里需要引入dubbo相关的依赖,非分布式项目这里无需引入-->
    <!-- 1、定义表现层服务名称: 服务消费者名称 -->
    <dubbo:application name="shop-web-2" />
    <!-- 2、指定服务消费地址 -->
    <dubbo:registry address="zookeeper://192.168.11.11:2181" />
    <!-- 3、xml方式引入服务 -->
    <dubbo:reference id="sellerService"
        interface="com.it.manager.service.SellerService">
    </dubbo:reference>
    <!-- 4、使用注解方法引入服务 -->
    <dubbo:annotation package="com.it.shop.controller" />

    <!-- 四、注册认证类 -->
    <bean:bean id="userDetailService" class="com.it.manager.service.userDetailServiceImpl">
        <bean:property name="sellerService" ref="sellerService">

        </bean:property>
    </bean:bean>

</bean:beans>

用户注册时的加密

@RequestMapping("/register")
public Result add(UserEntity userEntity){
    //密码加密
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    String password = passwordEncoder.encode(userEntity.getPassword());
    userEntity.setPassword(password);
    try {
            UserService.register(userEntity);
            return new Result(true, "增加成功");
    } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, "增加失败");
    }
}

五、权限设置(注解方式)

在业务层方法上通过注解@PreAuthorize,配置调用方法需要的权限:
例如:@PreAuthorize(“hasAuthority(‘PRODUCT_LIST’)”)

/**
     * 
     * 查询所有商品
     * @PreAuthorize("hasAuthority('PRODUCT_LIST')")
     *   配置调用该业务层方法需要的权限为:PRODUCT_LIST
     *   该注解为,在调用业务方法之前验证权限
     * */
    @PreAuthorize("hasAuthority('PRODUCT_LIST')")
    @Transactional(propagation = Propagation.SUPPORTS ,readOnly = true)
    public PageInfo findAllProduct(Integer pageNum,Integer pageSize){
         PageHelper.startPage(pageNum, pageSize);
         List<Product> products = productDao.findAllProduct();
         PageInfo pageInfo = new PageInfo(products);
         return pageInfo;
    };