Spring Security基于角色的访问授权示例

今天我们将讨论基于角色的访问控制和授权的Spring安全实例。但是在阅读本篇文章之前,请先查看我的之前一篇关于“Spring 4 Security MVC登录注销示例”的文章,以获得关于Spring 4安全的基本知识。

Spring 安全角色

在这篇文章中,我们将讨论如何在Spring Web应用程序中定义、使用和管理“USER”、“ADMIN”等Spring安全角色。与我之前的文章一样,这篇文章的示例也是使用Spring 4 MVC安全与内存存储和Spring Java配置特性来开发应用程序。这意味着我们不会使用web.xml文件,也不会编写一行Spring XML配置。我们将使用“内存存储”选项来存储和管理用户凭据。我们将使用Spring 4.0.2.RELEASE、Spring STS 3.7 Suite IDE、Spring TC Server 3.1以及Java 1.8和Maven构建工具来开发这个示例。

Spring Security 基于角色的访问授权示例

    在Spring STS套件中创建一个名为“SpringMVCSecruityMavenRolesApp2”的“Simple Spring Web Maven”项目,具体详情如下。使用我之前帖子中的同一pom.xml文件,但进行以下更改。
<artifactId>SpringMVCSecruityMavenRolesApp</artifactId>

<build>
  <finalName>SpringMVCSecruityMavenRolesApp</finalName>
</build>
</project>
    使用我之前发布的所有Java和JSP文件。我们只讨论这里更新或新添加的内容。
    更新LoginSecurityConfig.java文件,配置用户角色,如“USER”和“ADMIN”。
    LoginSecurityConfig.java
package com.Olivia.spring.secuity.config;

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 LoginSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder authenticationMgr) throws Exception {
		authenticationMgr.inMemoryAuthentication()
			.withUser("jduser").password("jdu@123").authorities("ROLE_USER")
			.and()
			.withUser("jdadmin").password("jda@123").authorities("ROLE_USER","ROLE_ADMIN");
	}
	
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		
		http.authorizeRequests()
			.antMatchers("/homePage").access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")
			.antMatchers("/userPage").access("hasRole('ROLE_USER')")
			.antMatchers("/adminPage").access("hasRole('ROLE_ADMIN')")
			.and()
				.formLogin().loginPage("/loginPage")
				.defaultSuccessUrl("/homePage")
				.failureUrl("/loginPage?error")
				.usernameParameter("username").passwordParameter("password")				
			.and()
				.logout().logoutSuccessUrl("/loginPage?logout"); 
		
	}
}

代码解释

    在configureGlobal()方法中,我们添加了两个用户:一个具有“ROLE_USER”角色,另一个具有“ROLE_USER”和“ROLE_ADMIN”角色。这意味着第二个用户将充当管理员用户。通过这种方式,我们可以配置任意数量的用户和角色。
    我们可以使用authorities(ROLE)或roles(ROLE)方法来配置应用程序中的角色。
    authorities()和roles()方法的区别是:
  • authorities() needs complete role name like “ROLE_USER”
  • roles() needs role name like “USER”. It will automatically adds “ROLE_” value to this “USER” role name.
    在configure()方法中,我们已经定义了具有所需访问角色的不同URL。
antMatchers("/homePage")
   .access("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')")

这段代码片段配置了“/homePage”页面对USER和ADMIN角色都是可用的。

 .antMatchers("/userPage").access("hasRole('ROLE_USER')")
 .antMatchers("/adminPage").access("hasRole('ROLE_ADMIN')")

这段代码片段配置了“/userPage”只能被“USER”角色访问,“/adminPage”只能被“ADMIN”角色访问。如果其他角色访问这些页面,会得到“403访问被拒绝”错误消息。

    将LoginController.java控制器文件更新,定义如下的新URL访问路径。
    LoginController.java
package com.Olivia.spring.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class LoginController {

	@RequestMapping(value = { "/"}, method = RequestMethod.GET)
	public ModelAndView welcomePage() {
		ModelAndView model = new ModelAndView();
		model.setViewName("welcomePage");
		return model;
	}

	@RequestMapping(value = { "/homePage"}, method = RequestMethod.GET)
	public ModelAndView homePage() {
		ModelAndView model = new ModelAndView();
		model.setViewName("homePage");
		return model;
	}
	
	@RequestMapping(value = {"/userPage"}, method = RequestMethod.GET)
	public ModelAndView userPage() {
		ModelAndView model = new ModelAndView();
		model.setViewName("userPage");
		return model;
	}
	
	@RequestMapping(value = {"/adminPage"}, method = RequestMethod.GET)
	public ModelAndView adminPage() {
		ModelAndView model = new ModelAndView();
		model.setViewName("adminPage");
		return model;
	}
	
	@RequestMapping(value = "/loginPage", method = RequestMethod.GET)
	public ModelAndView loginPage(@RequestParam(value = "error",required = false) String error,
	@RequestParam(value = "logout",	required = false) String logout) {
		
		ModelAndView model = new ModelAndView();
		if (error != null) {
			model.addObject("error", "Invalid Credentials provided.");
		}

		if (logout != null) {
			model.addObject("message", "Logged out from JournalDEV successfully.");
		}

		model.setViewName("loginPage");
		return model;
	}

}

代码说明除了之前的示例外,这里我们添加了两个新的URL。

    “/用户页面”用于用户角色访问和执行普通用户活动。
    “/管理员页面”用于管理员角色访问和执行管理员用户活动。管理员角色也可以访问“/用户页面”URL。
    更新了homePage.jsp文件以提供用户和管理员角色的特定活动。
    homePage.jsp
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<a href="${pageContext.request.contextPath}/userPage">JD User</a> | <a href="${pageContext.request.contextPath}/adminPage">JD Admin</a> | <a href="javascript:document.getElementById('logout').submit()">Logout</a>

<h3>Welcome to JournalDEV Tutorials</h3>
<ul>
   <li>Java 8 tutorial</li>
   <li>Spring tutorial</li>
   <li>Gradle tutorial</li>
   <li>BigData tutorial</li>
</ul>

<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>

在这里,我们在顶部框架上增加了三个类似菜单选项。 “注销”在我之前的帖子中已经讨论过了。新添加的两个链接分别是:

    JD 用户:可由“用户”和“管理员”角色访问
    JD 管理员:仅限“管理员”角色访问

在实时应用中,我们只会将“JD用户”链接显示为“用户”角色,并隐藏“JD管理员”链接。为了测试“用户”角色是否可以访问并查看详细的错误信息,我们没有隐藏此链接。20. 添加新的adminPage.jsp文件作为“管理员”角色的主页。

<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<h3>Admin Page</h3>

<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
	<a href="javascript:document.getElementById('logout').submit()">Logout</a>
</c:if>
    新增userPage.jsp文件作为“USER”角色的主页。
    userPage.jsp
<%@taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core"%>
<h3>Welcome to JournalDEV Tutorials</h3>
<h3>User Page</h3>

<c:url value="/logout" var="logoutUrl" />
<form id="logout" action="${logoutUrl}" method="post" >
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:if test="${pageContext.request.userPrincipal.name != null}">
	<a href="javascript:document.getElementById('logout').submit()">Logout</a>
</c:if>

我们现在已经完成了应用程序的开发。现在是时候看看我们项目的最终结构并测试应用程序了。26. 最终项目结构如下:

Spring Security 角色示例应用测试

    在Spring STS IDE中,右键单击项目并选择“Run AS >> Run on Server”选项。
    将会访问默认的应用欢迎页面,如下所示:3. 单击“Login to JournalDEV”链接。现在您处于登录页面。
    5. 使用“USER”角色凭据首次登录:
    用户名:jduser 密码:jdu@123 现在我们将看到应用程序首页有3个菜单选项:“JD User”,“JD Admin”和“Logout”。单击“JD User”链接。由于我们使用“USER”角色凭据登录应用程序,我们可以访问此链接,如下所示。只需在Spring STS IDE中使用向后箭头,这次单击“JD Admin”链接。由于我们使用“USER”角色凭据登录,我们无法访问此链接。这就是为什么我们看到此错误消息:“403 Access is denied”。9. 现在注销并再次使用ADMIN角色凭据登录
    用户名:jdadmin 密码:jda@123 这次我们可以成功访问“JD Admin”链接,如下所示。测试“Logout”链接以退出应用程序。

这就是关于Spring安全角色示例的全部内容,用于提供对Web应用程序页面的授权访问。