1. 程式人生 > >SpringSecurity安全框架和Bcrypt加密

SpringSecurity安全框架和Bcrypt加密

SpringSecurity開發步驟

Spring Security是一個能夠為基於Spring的企業應用系統提供宣告式的安全訪問控制解決方案的安全框架。它提供了一組可以在Spring應用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反轉Inversion of Control ,DI:Dependency Injection 依賴注入)和AOP(面向切面程式設計)功能,為應用系統提供宣告式的安全訪問控制功能,減少了為企業系統安全控制編寫大量重複程式碼的工作

1.開發思路

1. 攔截使用者請求		登入頁的路徑為("../login" method="post")

2. 當前登陸的使用者是誰?

3. 配置訪問某一個資源需要什麼角色?

4. 當前登陸使用者具有什麼角色?

5. 認證/登陸	授權

2.開發步驟

1.第一步: 引入依賴(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檔案(spring配置檔案 + DelegatingFilterProxy-委託代理過濾器)
<?xmlversion="1.0"encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
    <!-- 載入spring的核心配置檔案 -->
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-security.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <!-- 配置一個攔截器 --> <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> </web-app>
3.配置spring配置檔案
<?xmlversion="1.0"encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
        xmlns:beans="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.xsd">

    <!-- security="none"設定此資源不被攔截 -->
    <http pattern="/login.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>

    <!-- 頁面攔截規則 -->
    <!--
        1. http : 表示頁面的攔截規則
        2. intercept-url: 表示攔截的頁面
            /*  表示的是該目錄下的資源,只包括本級目錄不包括下級目錄
            /** 表示的是該目錄以及該目錄下所有級別子目錄的資源
            use-expressions為是否使用使用 Spring 表示式語言(SpEL),預設為true ,如果開啟
        3. form-login: 表示開啟表單登陸功能
            3.1 login-page: 登陸頁
            3.2 default-target-url: 登陸成功後預設跳轉的頁面
            3.3 authentication-failure-url: 登陸失敗預設跳轉的頁面
            3.4 csrf disabled="true"關閉csrf ,如果不加會出現錯誤
            3.5 always-use-default-target: 指定了是否在身份驗證通過後總是跳轉到default-target-url屬性指定的URL
            3.6 logout : 登出操作
                logout-url : 退出的地址,預設的地址為 /logout
                logout-success-url: 預設為 index.html
        4. authentication-manager: 認證管理器, 判斷使用者需要什麼樣的角色
            user-service-ref: 全類名(該類實現了UserDetailsService介面)
    -->
    <http use-expressions="false">
        <!-- 當前使用者必須有ROLE_USER的角色 才可以訪問根目錄及所屬子目錄的資源 -->
        <intercept-url pattern="/**" access="ROLE_SELLER"/>
        <!--<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>-->
        <form-login login-page="/login.html" default-target-url="/admin/index.html"
                    authentication-failure-url="/login.html"
                    always-use-default-target="true"/>
        <csrf disabled="true"/>
        <headers>
            <frame-optionspolicy="SAMEORIGIN"/>
        </headers>
        <logout logout-url="" logout-success-url=""/>
    </http>
    <!-- 認證管理器 -->
    <authentication-manager>
        <!-- 引入認證類 -->
        <authentication-provider user-service-ref="userDetailService">
            <password-encoder ref="bcryptEncoder"></password-encoder>
        </authentication-provider>
    </authentication-manager>

    <!-- 認證類 -->
    <beans:bean id="userDetailService" class="com.oranges.service.UserDetailsServiceImpl">
        <!-- 依賴注入遠端的服務 -->
        <beans:property name="sellerService" ref="sellerService"></beans:property>
    </beans:bean>

    <!-- 引用dubbo 服務 -->
    <dubbo:application name="pinyougou-shop-web" />
    <dubbo:registry address="zookeeper://192.168.25.135:2181"/>
    <dubbo:reference id="sellerService"
                     interface="com.oranges.sellergoods.service.SellerService"></dubbo:reference>

    <beans:bean id="bcryptEncoder" 
                class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
    </beans:bean>
</beans:beans>
4.前端頁面的表單提交方式
<!-- 提交路徑必須為 login, 提交方式必須為post -->
<form action="../login" method="post">
    
</form>
5.獲取通過框架登陸後登陸者的姓名
@RestController
@RequestMapping("/login")
publicclassLoginController {
	@RequestMapping("name")
    publicMap name(){
		String name=SecurityContextHolder.getContext()
.getAuthentication().getName();
		Mapmap=newHashMap();
		map.put("loginName", name);
		returnmap ;
	}	
}
6.編輯後臺程式碼認證類
/**
 * 認證類
 */
public class UserDetailsServiceImpl implements UserDetailsService {

	// 呼叫遠端的服務, 這裡沒有配置包掃描, 採用配置檔案的方式進行注入
	private SellerService sellerService;
	
	public void setSellerService(SellerService sellerService) {
		this.sellerService = sellerService;
	}

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		System.out.println("經過了UserDetailsServiceImpl");
		//構建角色列表
		List<GrantedAuthority> grantAuths=new ArrayList();
		grantAuths.add(new SimpleGrantedAuthority("ROLE_SELLER"));
		
		// 查詢資料庫得到 使用者物件
		TbSeller seller = sellerService.findOne(username);
		if(seller!=null){
			// 判斷使用者的狀態
			if(seller.getStatus().equals("1")){
				//grantAuths 使用者所具有的角色
				return new User(username,seller.getPassword(),grantAuths);
			}else{
				return null;
			}			
		}else{
			return null;
		}
	}
}
6.登出登陸
<logout logout-url="" logout-success-url=""/>
<!-- 前臺頁面的提交路徑為 "../logout" -->

3.密碼加密: BCrypt

1.瞭解
使用者表的密碼通常使用MD5等不可逆演算法加密後儲存,為防止彩虹表破解更會先使用一個特定的字串(如域名)加密,然後再使用一個隨機的salt(鹽值)加密。特定字串是程式程式碼中固定的,salt是每個密碼單獨隨機,一般給使用者表加一個欄位單獨儲存,比較麻煩。BCrypt演算法將salt隨機並混入最終加密後的密碼,驗證時也無需單獨提供之前的salt,從而無需單獨處理salt問題。
2.加密實現: BCryptPasswordEncoder
@RequestMapping("/add")
public Result add(@RequestBodyTbSeller seller){
    //密碼加密
    BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    String password = passwordEncoder.encode(seller.getPassword());

    seller.setPassword(password);
    try{
        sellerService.add(seller);
        returnnew Result(true,"增加成功");
    }catch(Exception e){
        e.printStackTrace();
        returnnew Result(false,"增加失敗");
    }
}
3.spring檔案的配置: 告訴系統該密碼是以什麼樣子的形式加密的
<beans:bean id="bcryptEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<!-- 認證管理器 -->
<authentication-manager alias="authenticationManager">
	<authentication-provider user-service-ref='userDetailService'>
		<password-encoder ref="bcryptEncoder"></password-encoder>			
	</authentication-provider>
</authentication-manager>