اليوم سنتطرق إلى مثال عن الوصول والترخيص بناءً على الأدوار في أمان الربيع. ومع ذلك ، قبل قراءة هذه المقالة ، يرجى قراءة مقالتي السابقة حول “مثال الدخول والخروج في تطبيق Spring 4 Security”.
دور أمان الربيع
في هذه المقالة ، سنناقش كيفية تعريف واستخدام وإدارة أدوار أمان الربيع مثل “USER” و “ADMIN” في تطبيق الويب الربيع. مثل المقالة السابقة ، يستخدم هذا المثال أيضًا Spring 4 MVC Security مع In-Memory Store وميزة Spring Java Configuration لتطوير التطبيق. وهذا يعني أننا لن نستخدم ملف web.xml ولن نكتب سوى سطر واحد حتى من تكوين XML للربيع. سنستخدم خيار “In-Memory Store” لتخزين وإدارة بيانات اعتماد المستخدم. سنستخدم Spring 4.0.2.RELEASE ، Spring STS 3.7 Suite IDE ، Spring TC Server 3.1 مع Java 1.8 وأداة Maven لتطوير هذا المثال.
مثال على وصول وترخيص أمان الربيع بناءً على الأدوار
- إنشاء مشروع “Simple Spring Web Maven” في مجموعة Spring STS Suite مع التفاصيل التالية.
اسم المشروع: SpringMVCSecruityMavenRolesApp2. استخدم نفس ملف pom.xml من مشاركتي السابقة مع التغييرات التالية
<artifactId>SpringMVCSecruityMavenRolesApp</artifactId>
<build>
<finalName>SpringMVCSecruityMavenRolesApp</finalName>
</build>
</project>
- استخدم جميع ملفات Java و JSP من مشاركتي السابقة. سنناقش فقط المحتوى المحدث أو المضاف حديثًا هنا.
- قم بتحديث ملف LoginSecurityConfig.java لتكوين أدوار المستخدم مثل “USER” و “ADMIN”.
LoginSecurityConfig.java
package com.journaldev.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() methods:
- authorities() تحتاج إلى اسم دور كامل مثل “ROLE_USER”
- roles() تحتاج إلى اسم دور مثل “USER”. سيتم إضافة قيمة “ROLE_” تلقائيًا إلى اسم هذا الدور “USER”.
- في طريقة 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 Access is Denied”.
- تحديث ملف تحكم LoginController.java لتعريف مسارات وصول URL الجديدة كما هو موضح أدناه.
LoginController.java
package com.journaldev.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;
}
}
شرح الشفرة بالإضافة إلى المثال السابق، هنا أضفنا مساري وصول جديدين.
-
تستخدم “/userPage” من قبل دور المستخدم للوصول إلى الصفحة وأداء الأنشطة العادية للمستخدم.
-
تستخدم “/adminPage” من قبل دور المسؤول للوصول وأداء الأنشطة الخاصة بالمسؤول. يمكن لدور المسؤول الوصول إلى مسار “/userPage” أيضًا.
-
تم تحديث ملف 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 ليعمل كصفحة رئيسية لدور “المسؤول”.
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”.
<%@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 Roles Example Test
- انقر بزر الماوس الأيمن على المشروع في بيئة التطوير Spring STS واختر الخيار “تشغيل كـ >> تشغيل على الخادم”. سيتم الوصول إلى صفحة ترحيب التطبيق الافتراضية كما هو موضح أدناه:
3. انقر على رابط “تسجيل الدخول إلى JournalDEV”. الآن أنت على صفحة تسجيل الدخول.
5. قم بتسجيل الدخول الأول باستخدام بيانات اعتماد الدور “USER”:
اسم المستخدم: jduser كلمة المرور: jdu@123الآن سنرى صفحة البداية للتطبيق مع 3 خيارات من القوائم: “مستخدم JD”، “مدير JD”، و “تسجيل الخروج”. انقر على رابط “مستخدم JD”. نظرًا لأننا قمنا بتسجيل الدخول إلى التطبيق باستخدام بيانات اعتماد الدور “USER”، يمكننا الوصول إلى هذا الرابط كما هو موضح أدناه.
استخدم السهم الخلفي في بيئة التطوير Spring STS هذه المرة وانقر على رابط “مدير JD”.
نظرًا لأننا قمنا بتسجيل الدخول باستخدام بيانات اعتماد الدور “USER”، لا يمكننا الوصول إلى هذا الرابط. لهذا السبب رأينا رسالة الخطأ هذه: “403 الوصول مرفوض”.9. سجّل الدخول الآن مرة أخرى باستخدام بيانات اعتماد الدور “ADMIN”
اسم المستخدم: jdadmin كلمة المرور: jda@123 في هذا الوقت يمكننا الوصول بنجاح إلى رابط “مدير JD” كما هو موضح أدناه.اختبار رابط “تسجيل الخروج” للخروج من التطبيق.
ذلك كل شيء عن مثال أدوار أمان Spring لتوفير الوصول المصرح به إلى صفحات تطبيق الويب.