Spring Secrity與Hibernate基於角色登錄實例

這篇文章介紹瞭如何使用Hibernate設置來實現Spring Security基於角色登錄。程序會根據用戶分配的角色,使用Hibernate設置在用戶登錄後根據用戶角色重定向到不同的URL。

這篇文章是在 Spring Security Hibernate註釋實例 基礎上補充的, 並簡單地增加了基於角色的登錄功能。由於這個篇文章與 Spring Security Hibernate註解實例有 99% 是相同的,除了一些改變,我們就不在這裏重複的代碼。僅做了一些簡單地更改如下。

首先我們來看看整個工程目錄的結構,如下圖所示 - 
Spring
Spring

第1步:創建一個新客戶成功處理程序

這個類的目標是提供自定義的重定向功能。

package com.yiibai.springsecurity.configuration;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

@Component
public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler{

private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

@Override
protected void handle(HttpServletRequest request, 
  HttpServletResponse response, Authentication authentication) throws IOException {
    String targetUrl = determineTargetUrl(authentication);

    if (response.isCommitted()) {
        System.out.println("Can't redirect");
        return;
    }

    redirectStrategy.sendRedirect(request, response, targetUrl);
}

protected String determineTargetUrl(Authentication authentication) {
    String url="";

    Collection<? extends GrantedAuthority> authorities =  authentication.getAuthorities();

    List<String> roles = new ArrayList<String>();

    for (GrantedAuthority a : authorities) {
        roles.add(a.getAuthority());
    }

    if (isDba(roles)) {
        url = "/db";
    } else if (isAdmin(roles)) {
        url = "/admin";
    } else if (isUser(roles)) {
        url = "/home";
    } else {
        url="/accessDenied";
    }

    return url;
}

public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
    this.redirectStrategy = redirectStrategy;
}
protected RedirectStrategy getRedirectStrategy() {
    return redirectStrategy;
}

private boolean isUser(List<String> roles) {
    if (roles.contains("ROLE\_USER")) {
        return true;
    }
    return false;
}

private boolean isAdmin(List<String> roles) {
    if (roles.contains("ROLE\_ADMIN")) {
        return true;
    }
    return false;
}

private boolean isDba(List<String> roles) {
    if (roles.contains("ROLE\_DBA")) {
        return true;
    }
    return false;
}

請注意我們是如何擴展Spring SimpleUrlAuthenticationSuccessHandler類和覆蓋 handle() 方法,只是調用使用配置RedirectStrategy重定向[默認在這種情況下]URL,它是用戶定義determineTargetUrl方法返回。 這個方法從當前認證對象提取登錄用戶的角色,然後構造基於角色有相應的URL。最後是RedirectStrategy 負責Spring Security 框架內的所有重定向,將請求重定向到指定的URL。

第2步:註冊自定義成功處理程序使用[現有]Security配置

package com.yiibai.springsecurity.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.core.userdetails.UserDetailsService;

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
@Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;

@Autowired
CustomSuccessHandler customSuccessHandler;


@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests()
      //.antMatchers("/", "/home").permitAll()
      .antMatchers("/", "/home").access("hasRole('USER')")
      .antMatchers("/admin/\*\*").access("hasRole('ADMIN')")
      .antMatchers("/db/\*\*").access("hasRole('ADMIN') and hasRole('DBA')")
      //.and().formLogin().loginPage("/login")
      .and().formLogin().loginPage("/login").successHandler(customSuccessHandler)
      .usernameParameter("ssoId").passwordParameter("password")
      .and().csrf()
      .and().exceptionHandling().accessDeniedPage("/Access\_Denied");
}

}

這裏相比之前 Hibernate 文章中的變化是額外調用 successHandler()如下所示:

formLogin().loginPage("/login").successHandler(customSuccessHandler).
我們來看看 successHandler。這個類基於自定義邏輯負責最後的重定向,這對我們來說是用戶的重定向[home/admin/db]是根據他的角色[USER/ADMIN/DBA]。

此外,我們根據用戶角色保護了主頁,使例子更貼近現實。

剛剛在配置包添加這個類並將其註冊爲成功處理程序來使用Security配置(如上圖所示)。

以上對應的XML配置格式的安全配置是:

<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-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">

<http auto-config="true" >
    <intercept-url pattern="/" access="permitAll" />
    <intercept-url pattern="/home" access="permitAll" />
    <intercept-url pattern="/admin\*\*" access="hasRole('ADMIN')" />
    <intercept-url pattern="/dba\*\*" access="hasRole('ADMIN') and hasRole('DBA')" />
    <form-login  login-page="/login" 
                 username-parameter="ssoId" 
                 password-parameter="password" 
                 authentication-success-handler-ref="customSuccessHandler"
                 authentication-failure-url="/Access\_Denied" />
    <csrf/>
</http>

<authentication-manager >
    <authentication-provider user-service-ref="customUserDetailsService"/>
</authentication-manager>

<beans:bean id="customUserDetailsService" class="com.yiibai.springsecurity.service.CustomUserDetailsService" />
<beans:bean id="customSuccessHandler"     class="com.yiibai.springsecurity.configuration.CustomSuccessHandler" />

構建和部署應用程序

現在構造 war(通過 eclipse/m2eclipse)或通過Maven的命令行(mvn clean install)。部署WAR文件到Servlet3.0容器。由於這裏我使用的是在 eclipse 中配置 Tomcat,可以直接發佈到 Tomcat 服務容器中。如果不知道怎麼使用,可以參考:http://www.yiibai.com/maven/create-a-maven-web-project-with-eclipse.html

運行應用程序

僅供參考,我們將使用在上一節中的所定義的數據庫表結構及數據記錄。點擊查看數據庫表和記錄 。

打開瀏覽器並訪問 - http://localhost:8080/SpringSecurityHibernateRoleBasedLogin/

結果如下所示 - 

Spring

提供DBA登錄帳戶信息,這裏使用 kenny 作爲登錄名。

Spring

提交後登錄成功後,你會被直接跳轉到 /db 頁面, kenny具有DBA角色。如下圖中所示 - 

Spring

現在註銷,並填寫一個一般用戶角色的用戶名,執行登錄測試跳轉 -

Spring

這裏爲了演示,故意寫錯了登錄密碼,如下所示 - 
Spring

提供正確的用戶(USER )角色的憑據,您將被重定向到主頁。

Spring

現在嘗試訪問管理頁面: http://localhost:8080/SpringSecurityHibernateRoleBasedLogin/admin 。您應該看到拒絕訪問頁面。如下圖中所示 - 

Spring

現在,註銷和管理員(ADMIN)憑據登錄,這裏使用一個叫作:sam 的用戶登錄,您將會被跳轉到URL:/admin。如下圖中所示 - 

Spring

最後,註銷登錄-

Spring

就這樣。下一篇文章我們將來學習在 Spring Security 中 使用BCryptPasswordEncoder密碼編碼

下載源代碼   

09-SpringSecurityHibernateRoleBasedLogin.zip

參考