تحية ، أصدقاء! سيبدأ غدًا الفصول الأولى في السلسلة الجديدة للدورة
"Developer on Spring Framework" في هذا الصدد ، نشارك تقليديا مواد مفيدة حول هذا الموضوع.

في هذه المقالة ، سوف نستكشف استخدام OAuth2 و JWT بالاقتران مع Spring Boot و Spring Security.
خادم التخويل
يعد خادم التخويل هو المكون الأكثر أهمية في بنية أمان واجهة برمجة تطبيقات الويب. يعمل خادم التخويل كنقطة تفويض واحدة ويسمح للتطبيقات ونقاط نهاية HTTP بتعريف وظائف التطبيق الخاص بك.
خادم الموارد
يوفر خادم التخويل للعملاء رمز وصول للوصول إلى خادم موارد نقاط نهاية HTTP. خادم الموارد عبارة عن مجموعة من المكتبات التي تحتوي على نقاط نهاية HTTP وموارد ثابتة وصفحات ويب ديناميكية.
في OAuth2
OAuth2 هو بروتوكول ترخيص يسمح للعميل (جهة خارجية) بالوصول إلى موارد التطبيق الخاص بك. لإنشاء تطبيق OAuth2 ، نحتاج إلى معرفة نوع المنحة (رمز التفويض) ، معرف العميل ، وسر العميل.
رمز JWT
رمز JWT هو رمز ويب JSON. يتم استخدامه لتمثيل معلومات الهوية الآمنة (المطالبات) بين الطرفين. يمكنك العثور على مزيد من المعلومات حول الرموز JWT على
www.jwt.io.سنقوم بإنشاء تطبيق OAuth2 باستخدام رموز JWT ، والتي ستتضمن خادم ترخيص وخادم مورد.
أولاً ، نحتاج إلى إضافة تبعيات إلى ملف البناء الخاص بنا.
يمكن لمستخدمي Maven إضافة التبعيات التالية إلى
pom.xml
.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency>
ملاحظة المترجم - بالنسبة إلى java الأقدم من 9 ، يجب عليك أيضًا إضافة التبعيات التالية: <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency>
يمكن لمستخدمي Gradle إضافة التبعيات التالية إلى ملف
build.gradle
.
compile('org.springframework.boot:spring-boot-starter-security') compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('org.springframework.security:spring-security-test') compile("org.springframework.security.oauth:spring-security-oauth2") compile('org.springframework.security:spring-security-jwt') compile("org.springframework.boot:spring-boot-starter-jdbc") compile("com.h2database:h2:1.4.191")
حيث،
- ربيع التمهيد كاتب الأمن - تنفذ ربيع الأمن
- Spring Security OAuth2 - تنفذ هياكل OAUTH2 لتشغيل خادم التخويل وخادم الموارد.
- Spring Security JWT - يولد الرموز JWT
- Spring Boot Starter JDBC - الوصول إلى قاعدة البيانات للتحقق من المستخدم.
- Spring Boot Starter Web - يوفر نقاط نهاية HTTP.
- قاعدة بيانات H2 - تخزن معلومات المستخدم للمصادقة والترخيص.
ويرد ملف
pom.xml
الكامل أدناه.
<?xml version = "1.0" encoding = "UTF-8"?> <project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.tutorialspoint</groupId> <artifactId>websecurityapp</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>websecurityapp</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.9.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Gradle — build.gradle
buildscript { ext { springBootVersion = '1.5.9.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' group = 'com.tutorialspoint' version = '0.0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile('org.springframework.boot:spring-boot-starter-security') compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test') testCompile('org.springframework.security:spring-security-test') compile("org.springframework.security.oauth:spring-security-oauth2") compile('org.springframework.security:spring-security-jwt') compile("org.springframework.boot:spring-boot-starter-jdbc") compile("com.h2database:h2:1.4.191") }
الآن ، قم بإضافة التعليقات التوضيحية
@EnableResourceServer
و
@EnableResourceServer
إلى ملف تطبيق Spring Boot الرئيسي بحيث يعمل التطبيق
@EnableResourceServer
تخويل وخادم مورد.
أضف أيضًا HTTP Endpoint (/ منتجات) بسيطة للوصول إلى واجهة برمجة تطبيقات Spring Security المحمية باستخدام رمز JWT.
package com.tutorialspoint.websecurityapp; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @EnableAuthorizationServer @EnableResourceServer @RestController public class WebsecurityappApplication { public static void main(String[] args) { SpringApplication.run(WebsecurityappApplication.class, args); } @RequestMapping(value = "/products") public String getProductName() { return "Honey"; } }
تحديد فئة POJO لتخزين معلومات مصادقة المستخدم.
package com.tutorialspoint.websecurityapp; import java.util.ArrayList; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; public class UserEntity { private String username; private String password; private Collection<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>(); public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Collection<GrantedAuthority> getGrantedAuthoritiesList() { return grantedAuthoritiesList; } public void setGrantedAuthoritiesList(Collection<GrantedAuthority> grantedAuthoritiesList) { this.grantedAuthoritiesList = grantedAuthoritiesList; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } }
بعد ذلك ، للمصادقة ، قم بإضافة فئة CustomUser ، والتي تمد
org.springframework.security.core.userdetails.User
.
package com.tutorialspoint.websecurityapp; import org.springframework.security.core.userdetails.User; public class CustomUser extends User { private static final long serialVersionUID = 1L; public CustomUser(UserEntity user) { super(user.getUsername(), user.getPassword(), user.getGrantedAuthoritiesList()); } }
قم بإنشاء
@Repository-
لاسترداد معلومات المستخدم من قاعدة البيانات وإضافة امتيازات ROLE_SYSTEMADMIN. سيتم استخدام هذه الفئة أيضًا في
CustomDetailsService
.
package com.tutorialspoint.websecurityapp; import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Repository; @Repository public class OAuthDao { @Autowired private JdbcTemplate jdbcTemplate; public UserEntity getUserDetails(String username) { Collection<GrantedAuthority> grantedAuthoritiesList = new ArrayList<>(); String userSQLQuery = "SELECT * FROM USERS WHERE USERNAME=?"; List<UserEntity> list = jdbcTemplate.query(userSQLQuery, new String[] { username }, (ResultSet rs, int rowNum) -> { UserEntity user = new UserEntity(); user.setUsername(username); user.setPassword(rs.getString("PASSWORD")); return user; }); if (list.size() > 0) { GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_SYSTEMADMIN"); grantedAuthoritiesList.add(grantedAuthority); list.get(0).setGrantedAuthoritiesList(grantedAuthoritiesList); return list.get(0); } return null; } }
للاتصال بمستودع DAO ، يمكنك إنشاء
UserDetailsService
الخاصة بك ، وراثة من
org.springframework.security.core.userdetails.UserDetailsService
، كما هو موضح أدناه.
package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; @Service public class CustomDetailsService implements UserDetailsService { @Autowired OAuthDao oauthDao; @Override public CustomUser loadUserByUsername(final String username) throws UsernameNotFoundException { UserEntity userEntity = null; try { userEntity = oauthDao.getUserDetails(username); CustomUser customUser = new CustomUser(userEntity); return customUser; } catch (Exception e) { e.printStackTrace(); throw new UsernameNotFoundException("User " + username + " was not found in the database"); } } }
بعد ذلك ، قم بإنشاء
@onfiguration-
لتمكين
Web Security
. تحديد معلمات تشفير كلمة المرور (
BCryptPasswordEncoder
)
BCryptPasswordEncoder
AuthenticationManager
فيه.
يجب أن ترث فئة
SecurityConfiguration
من فئة
WebSecurityConfigurerAdapter
.
package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private CustomDetailsService customDetailsService; @Bean public PasswordEncoder encoder() { return new BCryptPasswordEncoder(); } @Override @Autowired protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(customDetailsService).passwordEncoder(encoder()); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().anyRequest().authenticated().and().sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.NEVER); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring(); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } }
أضف الآن فصلاً لتكوين OAuth2. في ذلك ، حدد معرف العميل ، عميل العميل ، JwtAccessTokenConverter ، والمفاتيح الخاصة والعامة للتوقيع والتحقق من الرمز المميز ، وتكوين
ClientDetailsServiceConfigurer
رمزية صالحة.
package com.tutorialspoint.websecurityapp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; @Configuration public class OAuth2Config extends AuthorizationServerConfigurerAdapter { private String clientid = "tutorialspoint"; private String clientSecret = "my-secret-key"; private String privateKey = "private key"; private String publicKey = "public key"; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Bean public JwtAccessTokenConverter tokenEnhancer() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(privateKey); converter.setVerifierKey(publicKey); return converter; } @Bean public JwtTokenStore tokenStore() { return new JwtTokenStore(tokenEnhancer()); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore()) .accessTokenConverter(tokenEnhancer()); } @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory().withClient(clientid).secret(clientSecret).scopes("read", "write") .authorizedGrantTypes("password", "refresh_token").accessTokenValiditySeconds(20000) .refreshTokenValiditySeconds(20000); } }
الآن قم بإنشاء المفاتيح الخاصة والعامة باستخدام
openssl
.
لإنشاء مفتاح خاص ، يمكنك استخدام الأوامر التالية -
openssl genrsa -out jwt.pem 2048 openssl rsa -in jwt.pem
للمفتاح العام -
openssl rsa -in jwt.pem -pubout
لـ Spring Boot الأقدم من الإصدار 1.5 ، أضف الخاصية التالية إلى ملف
application.properties
(لتحديد ترتيب التصفية لموارد OAuth2).
security.oauth2.resource.filter-order=3
إذا كنت تستخدم ملف YAML ، أضف ما يلي.
security: oauth2: resource: filter-order: 3
الآن قم بإنشاء
data.sql
و
data.sql
في
classpath
في دليل
src/main/resources/directory
لتوصيل التطبيق بقاعدة بيانات H2.
يبدو ملف
schema.sql
كما يلي:
CREATE TABLE USERS (ID INT PRIMARY KEY, USERNAME VARCHAR(45), PASSWORD VARCHAR(60)); data.sql: INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES ( 1, 'tutorialspoint@gmail.com','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG'); INSERT INTO USERS (ID, USERNAME,PASSWORD) VALUES ( 2, 'myemail@gmail.com','$2a$08$fL7u5xcvsZl78su29x1ti.dxI.9rYO8t0q5wk2ROJ.1cdR53bmaVG');
ملاحظة - يجب تخزين كلمة المرور في جدول قاعدة البيانات بتنسيق Bcrypt Encoder.
يمكنك إنشاء ملف JAR قابل للتنفيذ وتشغيل تطبيق Spring Boot باستخدام أوامر Maven أو Gradle التالية.
بالنسبة إلى Maven ، يمكنك استخدام الأمر أدناه -
mvn clean install
بعد "BUILD SUCCESS" ، يمكنك العثور على ملفات JAR في الدليل
target
.
بالنسبة إلى Gradle ، يمكنك استخدام الأمر -
gradle clean build
بعد "BUILD SUCCESSFUL" ، يمكنك العثور على ملفات JAR في دليل
build/libs
.
الآن قم بتشغيل ملف JAR باستخدام الأمر -
java –jar <
JARFILE
>
تم إطلاق التطبيق في Tomcat على المنفذ 8080.

أرسل الآن طلب POST عبر POSTMAN لتلقي رمز OAUTH2.
http://localhost:8080/oauth/token
أضف الآن رؤوس الطلبات -
- التفويض - أساسي مع معرف العميل وسر العميل.
- نوع المحتوى - application / x-www-form-urlencoded

وطلب المعلمات -
- grant_type = كلمة المرور
- اسم المستخدم = اسمك
- كلمة المرور = كلمة المرور الخاصة بك

الآن قم بتشغيل واحصل على
access_token
كما هو موضح.

الآن قم بإنشاء طلب إلى خادم المورد API مع رمز لحامل في الرأس.

نحصل على النتيجة كما هو موضح أدناه.

نحن في انتظار تعليقاتك ، وكذلك إبلاغ أنه يمكنك
الانضمام إلى الدورة بسعر خاص حتى 31 مايو.