Spring Security 4 基于角色的登录例子(带源码)

原文网址: http://websystique.com/spring-security/spring-security-4-role-based-login-example/

【相关已翻译的本系列其他文章,点击分类里面的spring security 4】

【翻译by 明明如月 QQ 605283073】

上一篇: 

Spring Security 4 安全视图片段 使用标签(Spring Security 标签)

下一篇: 

Spring Security 4 Hibernate整合 注解和xml例子(带源码)

本教程将向你展示Spring Security 中基于 角色的登录。也就是说,根据其角色登录以后重定向到不同的url。



一般来说,我们需要自定义一个Success-Handler 来根据用户角色处理登录用户的重定向到对应的url

这个功能在Spring Security 里面已经提供了。

SimpleUrlAuthenticationSuccessHandler 含有常用的success handler的常用逻辑。

我们仅需要拓展它,实现我们自己的逻辑即可。

一旦我们获得了successhandler(处理器),我们将通过formLogin()或loginPage()来注册它,

完整的例子如下:

--------------------------------------------------------

下面是用的技术

  • Spring 4.1.6.RELEASE
  • Spring Security 4.0.1.RELEASE
  • Maven 3
  • JDK 1.7
  • Tomcat 8.0.21
  • Eclipse JUNO Service Release 2

让我们开始吧

第1步: 项目文件目录结构

下面是最终的项目目录结构
Spring Security 4 基于角色的登录例子(带源码)_第1张图片
现在让我为你展示上面目录结构里面的内容和每个的详细介绍。

第2步: 更新 pom.xml 包含所需的依赖


  4.0.0
 
  com.websystique.springsecurity
  SpringSecurityRoleBasedLoginExample
  1.0.0
  war
 
  SpringSecurityRoleBasedLoginExample
 
    
        4.1.6.RELEASE
        4.0.1.RELEASE
    
 
    
        
        
            org.springframework
            spring-core
            ${springframework.version}
        
        
            org.springframework
            spring-web
            ${springframework.version}
        
        
            org.springframework
            spring-webmvc
            ${springframework.version}
        
 
        
        
            org.springframework.security
            spring-security-web
            ${springsecurity.version}
        
        
            org.springframework.security
            spring-security-config
            ${springsecurity.version}
        
 
        
            javax.servlet
            javax.servlet-api
            3.1.0
        
        
            javax.servlet.jsp
            javax.servlet.jsp-api
            2.3.1
        
        
            javax.servlet
            jstl
            1.2
        
    
 
    
        
            
                
                    org.apache.maven.plugins
                    maven-compiler-plugin
                    3.2
                    
                        1.7
                        1.7
                    
                
                
                    org.apache.maven.plugins
                    maven-war-plugin
                    2.4
                    
                        src/main/webapp
                        SpringSecurityRoleBasedLoginExample
                        false
                    
                
            
        
        SpringSecurityRoleBasedLoginExample
    

第3步: 添加 Spring Security 配置类

添加spring security到我们应用中第一步是要创建Spring Security Java 配置类。

这个配置创建一个叫springSecurityFilterChain的Servlet过滤器,来对我们应用中所有的安全相关的事项(保护应用的所有url,验证用户名密码,表单重定向等)负责。

package com.websystique.springsecurity.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;
 
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
 
    @Autowired
    CustomSuccessHandler customSuccessHandler;
 
    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("bill").password("abc123").roles("USER");
        auth.inMemoryAuthentication().withUser("admin").password("root123").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("dba").password("root123").roles("ADMIN","DBA");
    }
 
    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
        .antMatchers("/", "/home").access("hasRole('USER')")
        .antMatchers("/admin/**").access("hasRole('ADMIN')")
        .antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
        .and().formLogin().loginPage("/login").successHandler(customSuccessHandler)
        .usernameParameter("ssoId").passwordParameter("password")
        .and().csrf()
        .and().exceptionHandling().accessDeniedPage("/Access_Denied");
    }
 
}

此类和前几篇文章类似,只是下面这点有区别: formLogin().loginPage("/login").successHandler(customSuccessHandler)

重点是successHandler,这个类定义了处理successHandler的逻辑。在本例中根据 角色USER/ADMIN/DBA重定向到home/admin/db 

以上配置 对应的xml配置文件:


      
    
        
        
        
        
        
        
    
  
    
        
            
                
                
                
            
        
    
      
    
     

下面是 上面的类里面涉及的 Success-Handler

package com.websystique.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);
    }
 
    /*
     * This method extracts the roles of currently logged-in user and returns
     * appropriate URL according to his/her role.
     */
    protected String determineTargetUrl(Authentication authentication) {
        String url = "";
 
        Collection authorities = authentication.getAuthorities();
 
        List roles = new ArrayList();
 
        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;
    }
 
    private boolean isUser(List roles) {
        if (roles.contains("ROLE_USER")) {
            return true;
        }
        return false;
    }
 
    private boolean isAdmin(List roles) {
        if (roles.contains("ROLE_ADMIN")) {
            return true;
        }
        return false;
    }
 
    private boolean isDba(List roles) {
        if (roles.contains("ROLE_DBA")) {
            return true;
        }
        return false;
    }
 
    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
        this.redirectStrategy = redirectStrategy;
    }
 
    protected RedirectStrategy getRedirectStrategy() {
        return redirectStrategy;
    }
 
}

注意:我们是怎样拓展 SimpleUrlAuthenticationSuccessHandler类的,重写了handle()方法,

简单的调用重定向使用配置的RedirectStrategy,其中通过determineTargetUrl方法返回对应的url 。

此方法从Authentication 对象中提取角色然后根据 角色构建 对应的url.最后在 Spring Security 负责所有重定向事务的RedirectStrategy (重定向策略)来重定向请求到指定的url

其余部分和以前的文章是一样的。

第4步: 注册springSecurityFilter

下面是定制初始化war包中的 springSecurityFilter(第三步中的) 注册类
package com.websystique.springsecurity.configuration;
 
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
 
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
 
}

上面配置对应的xml配置如下:


    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy

 

    springSecurityFilterChain
    /*

第5步: 添加 Controller(控制器)


package com.websystique.springsecurity.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;
 
@Controller
public class HelloWorldController {
 
     
    @RequestMapping(value = { "/", "/home" }, method = RequestMethod.GET)
    public String homePage(ModelMap model) {
        model.addAttribute("user", getPrincipal());
        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 = "/Access_Denied", method = RequestMethod.GET)
    public String accessDeniedPage(ModelMap model) {
        model.addAttribute("user", getPrincipal());
        return "accessDenied";
    }
 
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String loginPage() {
        return "login";
    }
 
    @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 "redirect:/login?logout";
    }
 
    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;
    }
 
}

第6步: 添加 SpringMVC 配置类


package com.websystique.springsecurity.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.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.JstlView;
 
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.websystique.springsecurity")
public class HelloWorldConfiguration extends WebMvcConfigurerAdapter{
     
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setViewClass(JstlView.class);
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");
 
        return viewResolver;
    }
 
     /*
     * Configure ResourceHandlers to serve static resources like CSS/ Javascript etc...
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }
}

---------译者增加 start---明明如月--------
以上配置对应的xml配置如下:
 
    /static/**" location="/static/" />
    
   
    
        
        
    
---------译者增加end---明明如月--------

第7: 添加Initializer(初始化器)类


package com.websystique.springsecurity.configuration;
 
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
 
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
 
    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[] { HelloWorldConfiguration.class };
    }
  
    @Override
    protected Class[] getServletConfigClasses() {
        return null;
    }
  
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
 
}

第8步: 添加视图

login.jsp
此视图为登录面板增加了css
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

    
        
        Login page
        
        
        
    
 
    
        
注意:和 CSRF 相关的是

这一行的目的是防止CSRF攻击。正如你所见jsp中CSRF参数使用EL表达式获取的。因此需要允许el表达式:
需要在jsp头添加如下一行:
<%@ page isELIgnored="false"%>

welcome.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>


    
    Welcome page


    Dear ${user}, Welcome to Home Page.
    ">Logout


admin.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>


    
    Admin page


    Dear ${user}, Welcome to Admin Page.
    ">Logout


dba.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>


    
    DBA page


    Dear ${user}, Welcome to DBA Page.
    ">Logout


accessDenied.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>


    
    AccessDenied page


    Dear ${user}, You are not authorized to access this page
    ">Logout

例子中所需的css文件

app.css

html{
    background-color:#2F2F2F;
}
 
body, #mainWrapper {
    height: 100%;
    background-image: -webkit-gradient(
    linear,
    right bottom,
    right top,
    color-stop(0, #EDEDED),
    color-stop(0.08, #EAEAEA),
    color-stop(1, #2F2F2F),
    color-stop(1, #AAAAAA)
);
background-image: -o-linear-gradient(top, #EDEDED 0%, #EAEAEA 8%, #2F2F2F 100%, #AAAAAA 100%);
background-image: -moz-linear-gradient(top, #EDEDED 0%, #EAEAEA 8%, #2F2F2F 100%, #AAAAAA 100%);
background-image: -webkit-linear-gradient(top, #EDEDED 0%, #EAEAEA 8%, #2F2F2F 100%, #AAAAAA 100%);
background-image: -ms-linear-gradient(top, #EDEDED 0%, #EAEAEA 8%, #2F2F2F 100%, #AAAAAA 100%);
background-image: linear-gradient(to top, #EDEDED 0%, #EAEAEA 8%, #2F2F2F 100%, #AAAAAA 100%);
}
 
body, #mainWrapper, .form-control{
    font-size:12px!important;
}
 
#mainWrapper {
    height: 100vh; 
    padding-left:10px;
    padding-right:10px;
    padding-bottom:10px;
}
 
#authHeaderWrapper{
    clear:both;
    width: 100%;
    height:3%;
    padding-top:5px;
    padding-bottom:5px;
}
 
.login-container {
    margin-top: 100px;
    background-color: floralwhite;
    width: 40%;
    left: 30%;
    position: absolute;
}
 
.login-card {
    width: 80%;
    margin: auto;
}
.login-form {
    padding: 10%;
}


第9步: 构建和部署应用

现在构建 war 包(通过eclipse或者myeclipse)或者通过maven 命令行(  mvn clean install). 在一个 Servlet 3.0 容器中发布本应用. 在这里我使用的是tomcat, 我将 war 文件放到  tomcat webapps 文件夹然后点击 tomcat安装目录的bin文件夹下的 start.bat .
启动应用
打开浏览器 在地址栏输入localhost:8080/SpringSecurityRoleBasedLoginExample/并回车

Spring Security 4 基于角色的登录例子(带源码)_第2张图片

输入DBA角色的账户

Spring Security 4 基于角色的登录例子(带源码)_第3张图片


提交表单,因为当前登录的用户时DBA角色,登录后将被重定向到/db 页面。

Spring Security 4 基于角色的登录例子(带源码)_第4张图片

退出后登录 USER权限的用户

Spring Security 4 基于角色的登录例子(带源码)_第5张图片

Spring Security 4 基于角色的登录例子(带源码)_第6张图片


然后访问 admin 页面,将看到 权限拒绝页面

Spring Security 4 基于角色的登录例子(带源码)_第7张图片

退出后登录 ADMIN 角色的账户

Spring Security 4 基于角色的登录例子(带源码)_第8张图片

本文结束,下一篇文章我们精介绍基于Hibernate注解的数据库的Spring Security 权限验证。

项目下载地址: http://websystique.com/?smd_process_download=1&download_id=1495

你可能感兴趣的:(翻译)