這篇文章主要記錄如何在Spring MVC專案中使用Spring Security模組來做Access的保護
一樣會透過一個簡單範例來介紹:

首先,一樣先放上最後建立好的專案結構,如下所示 :


1. 先在NetBeans中建立Maven的Web專案,並在pom.xml中加入所需的dependency

       <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springframework.version}</version>
        </dependency>
 
        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${springsecurity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${springsecurity.version}</version>
        </dependency>
        
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

2. 建立Spring Security要用到的Configuration Class (SecurityConfiguration.java)

package allen0818.practice.springsecurityprac.configuration;

import org.springframework.beans.factory.annotation.Autowired;
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;

/**
 *
 * @author allen0818
 */
 
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
 
    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("allen0818").password("123456").roles("USER");
        auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");//dba have two roles.
    }
     
    @Override
    protected void configure(HttpSecurity http) throws Exception {
  
      http.authorizeRequests()
        .antMatchers("/", "/home").permitAll() 
        .antMatchers("/admin/**").access("hasRole('ADMIN')")
        .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
        .and().formLogin()
        .and().exceptionHandling().accessDeniedPage("/Access_Denied");
    }
}
在這邊程式做了幾件事:
(1) 在configureGlobalSecurity這個方法中為特定的使用者綁定相對應的Role​​​
(2) 這邊採的是inMemory的認證機制,另外還有提供JDBC, LDAP ...等其他認證機制
(3) 在configure這個方法中我們設定了哪些路徑下只允許擁有哪些Role的使用者進入,permitAll()表示不用驗證可直接進入
(4) .formLogin()方法可讓Spring Security自動產生一個簡易的使用者認證頁面
(5) .exceptionHandling().accessDeniedPage用來導向所有產生403錯誤的頁面(即Access Denied的錯誤)

3. 建立一個Initial Class (SecurityWebApplicationInitializer.java),以註冊剛剛所建立的Configuration

package allen0818.practice.springsecurityprac.configuration;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;

/**
 *
 * @author allen0818
 */

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

}

4. 加入Controller (HelloWorldController.java)

package allen0818.practice.springsecurityprac.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 *
 * @author allen0818
 */

@Controller
public class HelloWorldController {
 
    @RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
    public String homePage(ModelMap model) {
        model.addAttribute("greeting", "Hi, Welcome to mysite. ");
        return "welcome";
    }
 
    @RequestMapping(value = "/admin", method = RequestMethod.GET)
    public String adminPage(ModelMap model) {
        model.addAttribute("user", getPrincipal());
        return "admin";
    }
 
    @RequestMapping(value = "/db", method = RequestMethod.GET)
    public String dbaPage(ModelMap model) {
        model.addAttribute("user", getPrincipal());
        return "dba";
    }
 
    @RequestMapping(value="/logout", method = RequestMethod.GET)
    public String logoutPage (HttpServletRequest request, HttpServletResponse response) {
       Authentication auth = SecurityContextHolder.getContext().getAuthentication();
       if (auth != null){    
          new SecurityContextLogoutHandler().logout(request, response, auth);
       }
       return "welcome";
    }
 
    @RequestMapping(value = "/Access_Denied", method = RequestMethod.GET)
    public String accessDeniedPage(ModelMap model) {
        model.addAttribute("user", getPrincipal());
        return "accessDenied";
    }
     
    private String getPrincipal(){
        String userName = null;
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
 
        if (principal instanceof UserDetails) {
            userName = ((UserDetails)principal).getUsername();
        } else {
            userName = principal.toString();
        }
        return userName;
    }
}
從程式碼中可以看到Spring Security如何封裝使用者的驗證資訊,並提供了Logout的方法

5. 建立Spring MVC的Configuration Class (SpringMvcConfiguration.java)

package allen0818.practice.springsecurityprac.configuration;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
 
/**
 *
 * @author allen0818
 */

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "allen0818.practice.springsecurityprac")
public class SpringMvcConfiguration {
     
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
 
        return viewResolver;
    }
}

6. 建立Spring MVC的Initializer Class(SpringMvcInitializer.java)

package allen0818.practice.springsecurityprac.configuration;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 *
 * @author allen0818
 */
 
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
 
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { SpringMvcConfiguration.class };
    }
  
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return null;
    }
  
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

7. 加入前端顯示所需要的views
welcome.jsp

<%-- 
    Document   : welcome
    Created on : 2016/5/11, 下午 04:06:15
    Author     : allen0818
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Welcome Page</title>
    </head>
    <body>
        Greeting : ${greeting}
        This is a welcome page.
    </body>
</html>

admin.jsp

<%-- 
    Document   : admin
    Created on : 2016/5/11, 下午 04:06:02
    Author     : allen0818
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Admin Page</title>
    </head>
    <body>
        Dear <strong>${user}</strong>, Welcome to Admin Page.
        <a href="<c:url value="/logout" />">Logout</a>
    </body>
</html>

dba.jsp

<%-- 
    Document   : dba
    Created on : 2016/5/11, 下午 04:06:08
    Author     : allen0818
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>DBA Page</title>
    </head>
    <body>
        Dear <strong>${user}</strong>, Welcome to DBA Page.
        <a href="<c:url value="/logout" />">Logout</a>
    </body>
</html>

accessDenied.jsp

<%-- 
    Document   : accessDenied
    Created on : 2016/5/11, 下午 04:05:53
    Author     : allen0818
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>AccessDenied Page</title>
    </head>
    <body>
        Dear <strong>${user}</strong>, You are not authorized to access this page
        <a href="<c:url value="/logout" />">Logout</a>
    </body>
</html>

呈現畫面如下(請觀察上方網址列):
1. welcome page

2. Spring Security提供的登入頁面

3. 登入失敗畫面

4. 進入未授權頁面畫面

5. Logout後導回至Welcome Page

還蠻多東西的,初次接觸的朋友可能需要好好消化一下~
這篇文章的內容主要是參考這篇教學整理而成,若需要有關Spring Security更詳細的介紹
可以參考官方釋出的document

參考資料:
1. http://websystique.com/spring-security/spring-security-4-hello-world-annotation-xml-example/
2. http://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/

 

 

 

 

 

arrow
arrow
    文章標籤
    Spring MVC Spring Security
    全站熱搜

    allen0818 發表在 痞客邦 留言(0) 人氣()