Sie sind auf Seite 1von 39

Notas Spring Framework

https://www.jcombat.com/spring

Understanding H2 InMemory
Database with Spring Boot
Introduction
Basically the database setup involves several steps before we can use it through configured datasource in
our application. This actually is required in case of actual project implementations. However, there are
situations where we just need a POC to be done for something, and the whole database setup thing still
becomes an obligation. Similarly, for unit tests, it would be ideal to have our own set of records in the
database, so its independent, without getting impacted by the data changes in the deployed environment.
For such use cases, in-memory databases are the ideal solution.

An in-memory database gets created when the application starts, while it gets destroyed when the
application stops.
Spring Boot integrates H2 database with lot of ease. So you can easily and quickly switch between a real
database and an in-memory database.

Note that, H2 InMemory Database is a relational DBMS written in Java.


Let’s check out a quick demo.
Implementation
Lets generate the Spring Boot project from Spring initializr. Ensure you add Web, JPA, H2 and
DevTools dependencies as shown below.

Let’s look at the generated pom file.

pom.xml
1 <?xml version="1.0" encoding="UTF-8"?>

2 <project xmlns="http://maven.apache.org/POM/4.0.0"

3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

5 <modelVersion>4.0.0</modelVersion>

7 <groupId>com.jcombat</groupId>

8 <artifactId>h2demo</artifactId>

9 <version>0.0.1-SNAPSHOT</version>
10 <packaging>jar</packaging>

11

12 <name>h2demo</name>

13 <description>Demo project for Spring Boot</description>

14

15 <parent>

16 <groupId>org.springframework.boot</groupId>

17 <artifactId>spring-boot-starter-parent</artifactId>

18 <version>2.1.0.RELEASE</version>

19 <relativePath /> <!-- lookup parent from repository -->

20 </parent>

21

22 <properties>

23 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

24 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

25 <java.version>1.8</java.version>

26 </properties>

27

28 <dependencies>

29 <dependency>

30 <groupId>org.springframework.boot</groupId>

31 <artifactId>spring-boot-starter-data-jpa</artifactId>

32 </dependency>

33 <dependency>

34 <groupId>org.springframework.boot</groupId>

35 <artifactId>spring-boot-starter-web</artifactId>

36 </dependency>

37

38 <dependency>

39 <groupId>org.springframework.boot</groupId>

40 <artifactId>spring-boot-devtools</artifactId>

41 <scope>runtime</scope>

42 </dependency>
43 <dependency>

44 <groupId>com.h2database</groupId>

45 <artifactId>h2</artifactId>

46 <scope>runtime</scope>

47 </dependency>

48 <dependency>

49 <groupId>org.springframework.boot</groupId>

50 <artifactId>spring-boot-starter-test</artifactId>

51 <scope>test</scope>

52 </dependency>

53 </dependencies>

54

55 <build>

56 <plugins>

57 <plugin>

58 <groupId>org.springframework.boot</groupId>

59 <artifactId>spring-boot-maven-plugin</artifactId>

60 </plugin>

61 </plugins>

62 </build>

63

64 </project>

We also notice application.properties file generated as –

application.properties
1 # H2

2 spring.h2.console.enabled=true

3 spring.h2.console.path=/h2

5 # Datasource

6 spring.datasource.url=jdbc:h2:mem:testdb

7 spring.datasource.username=sa

8 spring.datasource.password=

9 spring.datasource.driver-class-name=org.h2.Driver
The property spring.h2.console.enabled=true enables the web console at http://localhost:8080/h2

Click on Connect and you get into the page where you see available tables in the DB.

You might be wondering, how come Student table got created. The magic happens with data.sql placed
at src/main/resources. Just ensure you have the insert statements in the data.sql file as mentioned below

data.sql
1 insert into STUDENT

2 values(10001,'Ajay', 'AAA1');

4 insert into STUDENT

5 values(10002,'Ajit', 'AAA2');

Spring Boot Auto Configuration checks the values in the data.sql file and does the needful for you, i.e.
creates the STUDENT table, and executes the insert statements. Smart!
Lets check out how we can operate on these student records.

To do that, let’s have the Student entity class created now.

Student.java
1 package com.jcombat.entity;

3 import javax.persistence.Entity;

4 import javax.persistence.GeneratedValue;

5 import javax.persistence.Id;

7 @Entity

8 public class Student {

10 @Id

11 @GeneratedValue

12 private Long id;

13 private String name;

14 private String section;

15

16 public Student() {

17 }

18

19 public Student(Long id, String name, String section) {

20 this.id = id;

21 this.name = name;

22 this.section = section;

23 }

24

25 public Long getId() {

26 return id;

27 }

28

29 public void setId(Long id) {

30 this.id = id;

31 }

32

33 public String getName() {


34 return name;

35 }

36

37 public void setName(String name) {

38 this.name = name;

39 }

40

41 public String getSection() {

42 return section;

43 }

44

45 public void setSection(String section) {

46 this.section = section;

47 }

48

49 }

To access the database, let’s write a simple JPA interface which provides the required helper functions to
do basic DB operations.

StudentRepository.java
1 package com.jcombat.repository;

3 import org.springframework.data.jpa.repository.JpaRepository;

4 import org.springframework.stereotype.Repository;

6 import com.jcombat.entity.Student;

8 @Repository

9 public interface StudentRepository extends JpaRepository<Student, Long> {

10

11 }

Let’s now customize the Spring Boot entry point class using Command Line Runner, so we will be able
to execute our Spring Boot application from command line.

1 package com.jcombat.h2demo;
2

3 import org.slf4j.Logger;

4 import org.slf4j.LoggerFactory;

5 import org.springframework.beans.factory.annotation.Autowired;

6 import org.springframework.boot.CommandLineRunner;

7 import org.springframework.boot.SpringApplication;

8 import org.springframework.boot.autoconfigure.SpringBootApplication;

9 import org.springframework.boot.autoconfigure.domain.EntityScan;

10 import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

11

12 import com.jcombat.repository.StudentRepository;

13

14 @SpringBootApplication

15 @EntityScan("com.jcombat.entity")

16 @EnableJpaRepositories("com.jcombat.repository")

17 public class H2demoApplication implements CommandLineRunner {

18

19 // mvn spring-boot:run

20 private Logger LOG = LoggerFactory.getLogger("H2demoApplication");

21

22 StudentRepository studentRepository;

23

24 @Autowired

25 public H2demoApplication(StudentRepository studentRepository) {

26 this.studentRepository = studentRepository;

27 }

28

29 public static void main(String[] args) {

30 SpringApplication.run(H2demoApplication.class, args);

31 }

32

33 @Override

34 public void run(String... args) throws Exception {


35 LOG.info("Student count in DB: {}", studentRepository.count());

36 }

37 }

Executing the application


To run the application, you can either do it directly from your Eclipse IDE, or from command-line
through below command –

mvn spring-boot:run
When executed, we see the below output displayed on console –

Microservices implementation
example with Spring Boot
1. Introduction
We have already been through the Microservice demo and it was so pleasing to see the wonderful
response it received. Hopefully we are all good with the basics now. This tutorial will guide us all
through the actual Microservices implementation, so we are well-directed every time we are asked to
create it.
2. Understanding Service Registry
Traditionally, when we consume a REST service, we are usually provided with the network location of
the service instance (the REST service URLs that are usually static). However, this tradition has changed
with the Microservices architecture coming into picture. Lets understand, how!

In Microservices architecture, network locations of the service instances are dynamically


assigned/changed because of autoscaling, failures and upgrades. To comply with this
dynamicity, service discovery mechanismcomes in.

So there are two main service discovery patterns –

o client-side discovery
o server-side discovery
Client-side discovery
In client-side service discovery, client queries the Service Registry and determine the available service
instances using a separate load balancing mechanism. Load balancing usually works with Service
Registry to load balance requests across the available service instances. Each HTTP request is done
using one of the load balanced instance that is returned.

One of the major drawback is the tight coupling of client with Service Discovery and the Service
discovery logic needs to be written at the client end.

Server-side discovery
The client queries the Discovery Service via an abstraction layer, which is actually the load balancer or
we can say a router, that queries the Service Registry and routes the HTTP request to an available
service instance. Details of Service Discovery are abstracted (or hidden) from the client, as a result of
which the client don’t need to write the discovery logic, which lead to more ideal loose coupling of
client with the Service Discovery.

So what is Service Registry?


Service registry is the key part of service discovery mechanism. Service registry is a database of
available service instances. Service registry assures that its highly available and up to date with the
network locations of the services instances. Clients can cache network locations obtained from the
service registry, but as the network locations keep changing, the cache data soon becomes out of date.
To cope with this, it is the responsibility of Service Registry server (consists of a cluster of servers) to
maintain the consistency and keep refreshing the network location of the service instances (usually
refresh is done every 30 seconds).
One of most common example of a Service Registry is Netflix Eureka. It provides a REST API to
register (using a POST request) and query (using an HTTP GET request) service instances.
Netflix achieves the high availability by running one or more Eureka servers in each Amazon EC2
availability zone. Each Eureka in turn runs on an EC2 instance that has elastic IP address. DNS TEXT
records are used to store the Eureka cluster configuration (maps to the list of network locations of
Eureka servers), so that when Eureka server starts up, DNS is queried to retrieve the Eureka cluster
configuration (network locations of Eureka servers) and assigns itself an unused elastic IP address.
Hashicorp’s Consul and Apache Zookeeper are other examples of Service Registry.
Netflix Ribbon is an IPC (Inter Process Communication) client that works with Eureka to load balance
requests across the available service instances. The @LoadBalanced annotation configures
the RestTemplate to use Ribbon, which has been configured to use the Eureka client to query service
discovery and fetch available service instances.
3. Microservices Implementation
We will check out a simple demo on Microservices using Spring Boot. Hope we get more close to the
Microservices concept.

To create a Microservices system, we need to ensure of the below steps –

1. Creation of Eureka Discovery Server


o With Spring Boot, just one annotation @EnableEurekaServer does the job.
2. Creating Producer Microservice
o Register itself with Discovery Service
o @EnableDiscoveryClient activates the Netflix Eureka DiscoveryClient implementation
3. Create Consumer Microservice which finds the producer service instance registered with
Discovery Service
o Register itself with Discovery Service
o @EnableDiscoveryClient activates the Netflix Eureka DiscoveryClient implementation
o Requests for DiscoveryClient instance of Producer Microservice using a
smart RestTemplate.
4. We can then test end-to-end result by starting the Eureka service first. Once the Eureka service
starts up, start the discovery clients one after the other.
4. Testing the application
Once the Discovery service and Discovery client are started, we can check if the Discovery clients got
properly registered themselves with the Eureka Discovery server.

http://localhost:1111/
With Spring Boot all the implementation becomes so easy, just the right annotation at the right place
with minimal manual configuration.
We will now try running the application as mentioned below –

http://localhost:8080/
Securing resources using
Spring Security with OAuth

1. Introduction
In this tutorial, we will check out how we can use Spring Security with OAuth to secure the admin
resources on the server based on the path pattern (/api/**). Another path pattern (/oauth/token) we have
configured which will help configured authorization server generate the access token. Note that we will
be using Password Grant Type in this demo application.
Before we move on with the implementation, let’s recap on the events involved with this grant type.

2. Resource Owner Password Credentials Grant Type

o Used between trusted applications.


o The user (Resource Owner) shares the credentials directly with the client application, which
requests the Authorization Server to return the access token after successfully authenticating the
user credentials and further authorizing the user to access limited resources on the server.
Useful Links
o Learn more about other Authorization Grant Types
o Understanding OAuth2 token authentication
3. Implementation
Make sure the required pom entries are properly added to the pom.xml file.

pom.xml
1 <!-- Spring dependencies -->

2 <dependency>

3 <groupId>org.springframework</groupId>

4 <artifactId>spring-core</artifactId>

5 <version>${springframework.version}</version>

6 </dependency>

8 <dependency>

9 <groupId>org.springframework</groupId>

10 <artifactId>spring-web</artifactId>

11 <version>${springframework.version}</version>

12 </dependency>

13

14 <dependency>

15 <groupId>org.springframework</groupId>

16 <artifactId>spring-webmvc</artifactId>

17 <version>${springframework.version}</version>

18 </dependency>

19

20 <!-- Spring Security Dependencies -->

21 <dependency>

22 <groupId>org.springframework.security</groupId>

23 <artifactId>spring-security-core</artifactId>

24 <version>${spring-security.version}</version>

25 </dependency>

26 <dependency>

27 <groupId>org.springframework.security</groupId>

28 <artifactId>spring-security-web</artifactId>

29 <version>${spring-security.version}</version>

30 </dependency>

31 <dependency>

32 <groupId>org.springframework.security</groupId>

33 <artifactId>spring-security-config</artifactId>
34 <version>${spring-security.version}</version>

35 </dependency>

36 <dependency>

37 <groupId>org.springframework.security.oauth</groupId>

38 <artifactId>spring-security-oauth2</artifactId>

39 <version>${spring-security.oauth.version}</version>

40 </dependency>

web.xml
Update the web.xml file to load the context files and configure the Spring Security filter, which will
redirect the request for authentication and authorization before processing it.

1 <web-app xmlns="http://java.sun.com/xml/ns/javaee"

2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

3 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

4 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

5 version="3.0">

7 <display-name>Archetype Created Web Application</display-name>

9 <servlet>

10 <servlet-name>mvc-dispatcher</servlet-name>

11 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

12 <load-on-startup>1</load-on-startup>

13 </servlet>

14

15 <servlet-mapping>

16 <servlet-name>mvc-dispatcher</servlet-name>

17 <url-pattern>/</url-pattern>

18 </servlet-mapping>

19

20 <listener>

21 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

22 </listener>

23
24 <!-- Loads context files -->

25 <context-param>

26 <param-name>contextConfigLocation</param-name>

27 <param-value>

28 /WEB-INF/mvc-dispatcher-servlet.xml,

29 /WEB-INF/spring-security.xml

30 </param-value>

31 </context-param>

32

33 <!-- Spring Security -->

34 <filter>

35 <filter-name>springSecurityFilterChain</filter-name>

36 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

37 </filter>

38

39 <filter-mapping>

40 <filter-name>springSecurityFilterChain</filter-name>

41 <url-pattern>/*</url-pattern>

42 </filter-mapping>

43 </web-app>

mvc-dispatcher-servlet.xml
1 <?xml version="1.0" encoding="UTF-8"?>

2 <beans xmlns="http://www.springframework.org/schema/beans"

3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
4
xmlns:util="http://www.springframework.org/schema/util"
5 xmlns:mvc="http://www.springframework.org/schema/mvc"

6 xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
7
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
8
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
9
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-
10 3.2.xsd">

11

12 <context:component-scan base-package="com.jcombat" />


13 <mvc:annotation-driven />

14

15 <bean

16 class="org.springframework.web.servlet.view.InternalResourceViewResolver">

17 <property name="prefix">

18 <value>/WEB-INF/pages/</value>

19 </property>

20 <property name="suffix">

21 <value>.jsp</value>

22 </property>

</bean>

</beans>

Since we will are using admin JSP files, we have configured the corresponding view resolver for it.

Now let’s configure the Spring Security OAuth in its context file.

spring-security.xml
1
<?xml version="1.0" encoding="UTF-8" ?>
2
<beans xmlns="http://www.springframework.org/schema/beans"
3
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:oauth="http://www.springframework.org/schema/security/oauth2"

5 xmlns:context="http://www.springframework.org/schema/context"

6 xmlns:sec="http://www.springframework.org/schema/security"
xmlns:mvc="http://www.springframework.org/schema/mvc"
7
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2
8 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd

9 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd

10 http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-
security-3.2.xsd
11
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-
12 4.1.xsd

13 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-
4.1.xsd ">
14

15
<!-- Default url to get a token from OAuth -->
16
<http pattern="/oauth/token" create-session="stateless"
17
authentication-manager-ref="clientAuthenticationManager"
18
19 xmlns="http://www.springframework.org/schema/security">

20 <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />

21 <anonymous enabled="false" />

22 <http-basic entry-point-ref="clientAuthenticationEntryPoint" />

23 <custom-filter ref="clientCredentialsTokenEndpointFilter"

24 after="BASIC_AUTH_FILTER" />

25 <access-denied-handler ref="oauthAccessDeniedHandler" />

26 </http>

27

28 <!-- URLs should be protected and what roles have access to them -->

29 <!-- Can define more patterns based on the protected resources hosted on

30 the server -->

31 <http pattern="/api/**" create-session="never"

32 entry-point-ref="oauthAuthenticationEntryPoint"

33 access-decision-manager-ref="accessDecisionManager"

34 xmlns="http://www.springframework.org/schema/security">

35 <anonymous enabled="false" />

36 <intercept-url pattern="/api/**" access="ROLE_APP" />

37 <!-- Protect oauth clients with resource ids -->

38 <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />

39 <access-denied-handler ref="oauthAccessDeniedHandler" />

40 </http>

41

42 <bean id="oauthAuthenticationEntryPoint"

43 class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">

44 <property name="realmName" value="demo/client" />

45 </bean>

46

47 <bean id="clientAuthenticationEntryPoint"

48 class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">

49 <property name="realmName" value="demo/client" />

50 <property name="typeName" value="Basic" />

51 </bean>
52

53 <bean id="oauthAccessDeniedHandler"

54 class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

55

56 <bean id="clientCredentialsTokenEndpointFilter"

57
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
58
<property name="authenticationManager" ref="clientAuthenticationManager" />
59
</bean>
60

61
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
62
xmlns="http://www.springframework.org/schema/beans">
63
<constructor-arg>
64
<list>
65
<bean
66 class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />

67 <bean class="org.springframework.security.access.vote.RoleVoter" />


68 <bean class="org.springframework.security.access.vote.AuthenticatedVoter"
/>
69
</list>
70
</constructor-arg>
71
</bean>
72

73
<authentication-manager id="clientAuthenticationManager"
74
xmlns="http://www.springframework.org/schema/security">
75
<authentication-provider user-service-ref="clientDetailsUserService" />
76
</authentication-manager>
77

78
<!-- This is simple authentication manager, with a hard-coded username/password
79
combination. We can replace this with a user defined service to fetch user
80
credentials from DB instead -->
81
<authentication-manager alias="authenticationManager"
82
xmlns="http://www.springframework.org/schema/security">
83
<authentication-provider>
84
85 <user-service>

86 <user name="admin" password="123" authorities="ROLE_APP" />

87 </user-service>

88 </authentication-provider>

89 </authentication-manager>

90

91 <bean id="clientDetailsUserService"

92 class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">

93 <constructor-arg ref="clientDetails" />

94 </bean>

95

96 <!-- This defines the token store. We have currently used in-memory token

97 store but we can instead use a user defined one -->

98 <bean id="tokenStore"

99 class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

100 <!-- If need to store tokens in DB

101 <bean id="tokenStore"

102 class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">

103 <constructor-arg ref="jdbcTemplate" />

104 </bean> -->

105

106 <!-- This is where we defined token based configurations, token validity

107 and other things -->

108 <bean id="tokenServices"

109 class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">

110 <property name="tokenStore" ref="tokenStore" />

111 <property name="supportRefreshToken" value="true" />

112 <property name="accessTokenValiditySeconds" value="120" />

113 <property name="clientDetailsService" ref="clientDetails" />

114 </bean>

115

116 <bean id="userApprovalHandler"

117
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
118 <property name="tokenServices" ref="tokenServices" />

119 </bean>

120

121 <!-- The server issuing access tokens to the client after successfully authenticating

122 the resource owner and obtaining authorization -->

123 <oauth:authorization-server

124 client-details-service-ref="clientDetails" token-services-ref="tokenServices"

125 user-approval-handler-ref="userApprovalHandler">

126 <oauth:authorization-code />

127 <oauth:implicit />

128 <oauth:refresh-token />

129 <oauth:client-credentials />

130 <oauth:password />

131 </oauth:authorization-server>

132

133 <!-- Define protected resources hosted by the resource server -->

134 <oauth:resource-server id="resourceServerFilter"

135 resource-id="adminProfile" token-services-ref="tokenServices" />

136

137 <!-- OAuth clients allowed to access the protected resources, can be something

138 like facebook, google if we are sharing any resource with them -->

139 <oauth:client-details-service id="clientDetails">

140 <oauth:client client-id="fbApp"

141 authorized-grant-types="password,refresh_token"

142 secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" />

143 </oauth:client-details-service>

144

145 <sec:global-method-security

146 pre-post-annotations="enabled" proxy-target-class="true">

147 <sec:expression-handler ref="oauthExpressionHandler" />

</sec:global-method-security>

<oauth:expression-handler id="oauthExpressionHandler" />


<oauth:web-expression-handler id="oauthWebExpressionHandler" />

</beans>

We have configured /oauth/token URL for issuing access and refresh tokens and /api/** maps to the
actual protected resources on the server. Hence to access any URL matching the pattern /api/**, a valid
token needs to be passed along with the request.
Authentication Manager is the container where the authentication happens. In our case, the
authentication manager checks –
o If the user is authenticated.
o If the user has requested for the correct client-id.
o If the client-id is fine, is the user authorized to use it to access the admin profile on the server.
Refer to the below snippet –

1 <authentication-manager id="clientAuthenticationManager"

2 xmlns="http://www.springframework.org/schema/security">

3 <authentication-provider user-service-ref="clientDetailsUserService" />

4 </authentication-manager>

6 <bean id="clientDetailsUserService"

7 class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">

8 <constructor-arg ref="clientDetails" />

9 </bean>

10

11 <!-- OAuth clients allowed to access the protected resources, can be something

12 like facebook, google if we are sharing any resource with them -->

13 <oauth:client-details-service id="clientDetails">

14 <oauth:client client-id="fbApp"

15 authorized-grant-types="password,refresh_token"

16 secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" />

17 </oauth:client-details-service>

Once the user is authenticated, the authorization server calls the tokenServices and issues the access
token.
1 <oauth:authorization-server

2 client-details-service-ref="clientDetails" token-services-ref="tokenServices"

3 user-approval-handler-ref="userApprovalHandler">

4 <oauth:authorization-code />

5 <oauth:implicit />
6 <oauth:refresh-token />

7 <oauth:client-credentials />

8 <oauth:password />

9 </oauth:authorization-server>

10

11 <bean id="tokenServices"

12 class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">

13 <property name="tokenStore" ref="tokenStore" />

14 <property name="supportRefreshToken" value="true" />

15 <property name="accessTokenValiditySeconds" value="120" />

16 <property name="clientDetailsService" ref="clientDetails" />

17 </bean>

18

19 <bean id="tokenStore"

20 class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

21

22 <bean id="userApprovalHandler"

23
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
24
<property name="tokenServices" ref="tokenServices" />
25
</bean>

While specifying the clients, note the grant type we have specified, which is password.
1 <oauth:client-details-service id="clientDetails">

2 <oauth:client client-id="fbApp"

3 authorized-grant-types="password,refresh_token"

4 secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" />

5 </oauth:client-details-service>

Once the access token has been issued, we can access the protected resources on the server passing it
along with every request. Let’s finally take a look at the Spring Controller we have written –

DemoController.java
1 package com.jcombat.controller;

3 import org.springframework.stereotype.Controller;

4 import org.springframework.web.bind.annotation.RequestMapping;
5

6 @Controller

7 public class DemoController {

9 @RequestMapping("/api/admin")

10 public String getAdminPage() {

11 return "/secured/admin";

12 }

13 }

4. Running the application


To run the application, let’s start with requesting the access token from the authorization server –

http://localhost:8080/SpringSecurityOAuth/oauth/token?grant_type=password&client_id=fbApp&clien
t_secret=fbApp&username=admin&password=123
1{

2 "access_token":"5c0c1a28-9603-4818-9ebb-6014600c3de9",

3 "token_type":"bearer",

4 "refresh_token":"ada8a736-3082-4c3d-9cbf-f043ab8f415f",

5 "expires_in":119

6}

Once the access token is generated, we are ready to pass it along with every subsequent requests for the
protected resources on the server.

http://localhost:8080/SpringSecurityOAuth/api/admin?access_token=5c0c1a28-9603-4818-9ebb-
6014600c3de9
Secure REST Service with
OAuth2 Tokens
1. Introduction
In this tutorial, we will check out how we can use Spring Security with OAuth to secure REST Service.
In the demo application, the secured REST resources on the server are accessible with the path pattern
(/api/**), such that the request URLs based on this path are mapped to different controller methods. This
means that –
o Any REST request URL without ‘/api‘ in the path will stay invalid, as these won’t match to any of
the controller mappings.
o After the required OAuth2 configurations are done, any REST request URL without a token as
parameter will be unauthorized.
Another path pattern (/oauth/token) we have configured which will help configured authorization server
generate the access token. Note that we will be using Password Grant Type in this demo application.
Before we move on with the implementation, let’s recap on the events involved with this grant type.

2. Resource Owner Password Credentials Grant Type

o Used between trusted applications.


o The user (Resource Owner) shares the credentials directly with the client application, which
requests the Authorization Server to return the access token after successfully authenticating the
user credentials and further authorizing the user to access limited resources on the server.
Useful Links
o Learn more about other Authorization Grant Types
o Understanding OAuth2 token authentication
3. Implementation
Make sure the required pom entries are properly added to the pom.xml file.

pom.xml
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

3 <modelVersion>4.0.0</modelVersion>

4 <groupId>org.springframework.samples.service.service</groupId>

5 <artifactId>SecureRESTWithOAuth</artifactId>

6 <version>0.0.1-SNAPSHOT</version>

7 <packaging>war</packaging>

9 <dependencies>

10 <dependency>

11 <groupId>junit</groupId>

12 <artifactId>junit</artifactId>

13 <version>3.8.1</version>

14 <scope>test</scope>

15 </dependency>

16

17 <!-- Spring dependencies -->

18 <dependency>

19 <groupId>org.springframework</groupId>

20 <artifactId>spring-core</artifactId>

21 <version>4.2.1.RELEASE</version>

22 </dependency>

23

24 <dependency>

25 <groupId>org.springframework</groupId>

26 <artifactId>spring-web</artifactId>

27 <version>4.2.1.RELEASE</version>

28 </dependency>

29

30 <dependency>

31 <groupId>org.springframework</groupId>
32 <artifactId>spring-webmvc</artifactId>

33 <version>4.2.1.RELEASE</version>

34 </dependency>

35

36 <!-- Jackson JSON Processor -->

37 <dependency>

38 <groupId>com.fasterxml.jackson.core</groupId>

39 <artifactId>jackson-databind</artifactId>

40 <version>2.4.1</version>

41 </dependency>

42

43 <!-- Spring Security Dependencies -->

44 <dependency>

45 <groupId>org.springframework.security</groupId>

46 <artifactId>spring-security-core</artifactId>

47 <version>3.2.3.RELEASE</version>

48 </dependency>

49 <dependency>

50 <groupId>org.springframework.security</groupId>

51 <artifactId>spring-security-web</artifactId>

52 <version>3.2.3.RELEASE</version>

53 </dependency>

54 <dependency>

55 <groupId>org.springframework.security</groupId>

56 <artifactId>spring-security-config</artifactId>

57 <version>3.2.3.RELEASE</version>

58 </dependency>

59 <dependency>

60 <groupId>org.springframework.security.oauth</groupId>

61 <artifactId>spring-security-oauth2</artifactId>

62 <version>1.0.0.RELEASE</version>

63 </dependency>

64 </dependencies>
65 </project>

web.xml
Update the web.xml file to load the context files and configure the Spring Security filter, which will
redirect the request for authentication and authorization before processing it.

1 <?xml version="1.0" encoding="ISO-8859-1"?>

2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

3 xmlns="http://java.sun.com/xml/ns/javaee"

4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

5 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

6 id="WebApp_ID" version="2.5">

8 <display-name>SecureRESTWithOAuth</display-name>

10 <servlet>

11 <servlet-name>mvc-dispatcher</servlet-name>

12 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

13 <load-on-startup>1</load-on-startup>

14 </servlet>

15

16 <servlet-mapping>

17 <servlet-name>mvc-dispatcher</servlet-name>

18 <url-pattern>/*</url-pattern>

19 </servlet-mapping>

20

21 <listener>

22 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

23 </listener>

24

25 <!-- Loads context files -->

26 <context-param>

27 <param-name>contextConfigLocation</param-name>

28 <param-value>

29 /WEB-INF/mvc-dispatcher-servlet.xml,
30 /WEB-INF/spring-security.xml

31 </param-value>

32 </context-param>

33

34 <!-- Spring Security -->

35 <filter>

36 <filter-name>springSecurityFilterChain</filter-name>

37 <filter-class>org.springframework.web.filter.DelegatingFilterProxy

38 </filter-class>

39 </filter>

40

41 <filter-mapping>

42 <filter-name>springSecurityFilterChain</filter-name>

43 <url-pattern>/*</url-pattern>

44 </filter-mapping>

45

46 </web-app>

mvc-dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>

1 <beans xmlns="http://www.springframework.org/schema/beans"

2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
3
xmlns:util="http://www.springframework.org/schema/util"
4 xmlns:mvc="http://www.springframework.org/schema/mvc"

5 xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
6
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
7
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
8
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-
9 3.2.xsd">

10

11 <context:component-scan base-package="com.jcombat.controller" />


12 <mvc:annotation-driven />
13

</beans>
Since we will are using admin JSP files, we have configured the corresponding view resolver for it.

Now let’s configure the Spring Security OAuth in its context file.

spring-security.xml
1
<?xml version="1.0" encoding="UTF-8" ?>
2
<beans xmlns="http://www.springframework.org/schema/beans"
3
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:oauth="http://www.springframework.org/schema/security/oauth2"

5 xmlns:context="http://www.springframework.org/schema/context"

6 xmlns:sec="http://www.springframework.org/schema/security"
xmlns:mvc="http://www.springframework.org/schema/mvc"
7
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2
8 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd

9 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd

10 http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-
security-3.2.xsd
11
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-
12 4.1.xsd

13 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-
4.1.xsd ">
14

15
<!-- Default url to get a token from OAuth -->
16
<http pattern="/oauth/token" create-session="stateless"
17
authentication-manager-ref="clientAuthenticationManager"
18
xmlns="http://www.springframework.org/schema/security">
19
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
20
<anonymous enabled="false" />
21
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
22
<custom-filter ref="clientCredentialsTokenEndpointFilter"
23
after="BASIC_AUTH_FILTER" />
24
<access-denied-handler ref="oauthAccessDeniedHandler" />
25
</http>
26

27
<!-- URLs should be protected and what roles have access to them -->
28
<!-- Can define more patterns based on the protected resources hosted on
29
the server -->
30
31 <http pattern="/api/**" create-session="never"

32 entry-point-ref="oauthAuthenticationEntryPoint"

33 access-decision-manager-ref="accessDecisionManager"

34 xmlns="http://www.springframework.org/schema/security">

35 <anonymous enabled="false" />

36 <intercept-url pattern="/api/**" access="ROLE_APP" />

37 <!-- Protect oauth clients with resource ids -->

38 <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />

39 <access-denied-handler ref="oauthAccessDeniedHandler" />

40 </http>

41

42 <bean id="oauthAuthenticationEntryPoint"

43 class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">

44 <property name="realmName" value="demo/client" />

45 </bean>

46

47 <bean id="clientAuthenticationEntryPoint"

48 class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">

49 <property name="realmName" value="demo/client" />

50 <property name="typeName" value="Basic" />

51 </bean>

52

53 <bean id="oauthAccessDeniedHandler"

54 class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

55

56 <bean id="clientCredentialsTokenEndpointFilter"

57
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
58
<property name="authenticationManager" ref="clientAuthenticationManager" />
59
</bean>
60

61
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
62
xmlns="http://www.springframework.org/schema/beans">
63
<constructor-arg>
64 <list>

65 <bean
class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
66
<bean class="org.springframework.security.access.vote.RoleVoter" />
67
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"
68 />

69 </list>
70 </constructor-arg>
71 </bean>
72

73 <authentication-manager id="clientAuthenticationManager"
74 xmlns="http://www.springframework.org/schema/security">
75 <authentication-provider user-service-ref="clientDetailsUserService" />
76 </authentication-manager>
77

78 <!-- This is simple authentication manager, with a hard-coded username/password


79 combination. We can replace this with a user defined service to fetch user
80 credentials from DB instead -->
81 <authentication-manager alias="authenticationManager"
82 xmlns="http://www.springframework.org/schema/security">
83 <authentication-provider>
84 <user-service>
85 <user name="admin" password="123" authorities="ROLE_APP" />
86 </user-service>
87 </authentication-provider>
88 </authentication-manager>
89

90 <bean id="clientDetailsUserService"
91 class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
92 <constructor-arg ref="clientDetails" />
93 </bean>
94

95 <!-- This defines the token store. We have currently used in-memory token
96 store but we can instead use a user defined one -->
97 <bean id="tokenStore"

98 class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

99 <!-- If need to store tokens in DB

100 <bean id="tokenStore"

101 class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">

102 <constructor-arg ref="jdbcTemplate" />

103 </bean> -->

104

105 <!-- This is where we defined token based configurations, token validity

106 and other things -->

107 <bean id="tokenServices"

108 class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">

109 <property name="tokenStore" ref="tokenStore" />

110 <property name="supportRefreshToken" value="true" />

111 <property name="accessTokenValiditySeconds" value="120" />

112 <property name="clientDetailsService" ref="clientDetails" />

113 </bean>

114

115 <bean id="userApprovalHandler"

116
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
117
<property name="tokenServices" ref="tokenServices" />
118
</bean>
119

120
<!-- The server issuing access tokens to the client after successfully authenticating
121
the resource owner and obtaining authorization -->
122
<oauth:authorization-server
123
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
124
user-approval-handler-ref="userApprovalHandler">
125
<oauth:authorization-code />
126
<oauth:implicit />
127
<oauth:refresh-token />
128
<oauth:client-credentials />
129
<oauth:password />
130 </oauth:authorization-server>

131

132 <!-- Define protected resources hosted by the resource server -->

133 <oauth:resource-server id="resourceServerFilter"

134 resource-id="adminProfile" token-services-ref="tokenServices" />

135

136 <!-- OAuth clients allowed to access the protected resources, can be something

137 like facebook, google if we are sharing any resource with them -->

138 <oauth:client-details-service id="clientDetails">

139 <oauth:client client-id="fbApp"

140 authorized-grant-types="password,refresh_token"

141 secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" />

142 </oauth:client-details-service>

143

144 <sec:global-method-security

145 pre-post-annotations="enabled" proxy-target-class="true">

146 <sec:expression-handler ref="oauthExpressionHandler" />

147 </sec:global-method-security>

<oauth:expression-handler id="oauthExpressionHandler" />

<oauth:web-expression-handler id="oauthWebExpressionHandler" />

</beans>

We have configured /oauth/token URL for issuing access and refresh tokens and /api/** maps to the
actual protected resources on the server. Hence to access any URL matching the pattern /api/**, a valid
token needs to be passed along with the request.
Authentication Manager is the container where the authentication happens. In our case, the
authentication manager checks –
o If the user is authenticated.
o If the user has requested for the correct client-id.
o If the client-id is fine, is the user authorized to use it to access the admin profile on the server.
Refer to the below snippet –

1 <authentication-manager id="clientAuthenticationManager"

2 xmlns="http://www.springframework.org/schema/security">

3 <authentication-provider user-service-ref="clientDetailsUserService" />

4 </authentication-manager>
5

6 <bean id="clientDetailsUserService"

7 class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">

8 <constructor-arg ref="clientDetails" />

9 </bean>

10

11 <!-- OAuth clients allowed to access the protected resources, can be something

12 like facebook, google if we are sharing any resource with them -->

13 <oauth:client-details-service id="clientDetails">

14 <oauth:client client-id="fbApp"

15 authorized-grant-types="password,refresh_token"

16 secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" />

17 </oauth:client-details-service>

Once the user is authenticated, the authorization server calls the tokenServices and issues the access
token.
1 <oauth:authorization-server

2 client-details-service-ref="clientDetails" token-services-ref="tokenServices"

3 user-approval-handler-ref="userApprovalHandler">

4 <oauth:authorization-code />

5 <oauth:implicit />

6 <oauth:refresh-token />

7 <oauth:client-credentials />

8 <oauth:password />

9 </oauth:authorization-server>

10

11 <bean id="tokenServices"

12 class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">

13 <property name="tokenStore" ref="tokenStore" />

14 <property name="supportRefreshToken" value="true" />

15 <property name="accessTokenValiditySeconds" value="120" />

16 <property name="clientDetailsService" ref="clientDetails" />

17 </bean>

18

19 <bean id="tokenStore"
20 class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />

21

22 <bean id="userApprovalHandler"

23
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
24
<property name="tokenServices" ref="tokenServices" />
25
</bean>

While specifying the clients, note the grant type we have specified, which is password.
1 <oauth:client-details-service id="clientDetails">

2 <oauth:client client-id="fbApp"

3 authorized-grant-types="password,refresh_token"

4 secret="fbApp" authorities="ROLE_APP" resource-ids="adminProfile" />

5 </oauth:client-details-service>

Once the access token has been issued, we can access the protected resources on the server passing it
along with every request. Let’s finally take a look at the Spring Controller we have written –

EmployeeController.java
1
package com.jcombat.controller;
2

3
import org.springframework.web.bind.annotation.PathVariable;
4
import org.springframework.web.bind.annotation.RequestMapping;
5
import org.springframework.web.bind.annotation.RequestMethod;
6
import org.springframework.web.bind.annotation.RequestParam;
7
import org.springframework.web.bind.annotation.RestController;
8

9
import com.jcombat.bean.Employee;
10

11
@RestController
12
@RequestMapping(value = "/api/Employee")
13
public class EmployeeController {
14

15
@RequestMapping(value = "/{name}", method = RequestMethod.GET)
16
public Employee process(
17
@PathVariable("name") String name,
18
19 @RequestParam(value = "empId", required = false, defaultValue = "00000") final
String id) {
20
Employee employee = new Employee();
21
employee.setEmpId(id);
22
employee.setName(name);
23
return employee;
24
}

4. Running the application


To run the application, let’s start with requesting the access token from the authorization server –

http://localhost:8080/SecureRESTWithOAuth/oauth/token?grant_type=password&client_id=fbApp&cl
ient_secret=fbApp&username=admin&password=123
1 {

2 "value":"a7718567-6e38-4be3-aa41-382c90e042e0",

3 "expiration":1505631027817,

4 "tokenType":"bearer",

5 "refreshToken":{

6 "value":"7792b077-7ae0-427e-8170-8b1440e5fefd",

7 "expiration":1508222907814

8 },

9 "scope":[

10

11 ],

12 "additionalInformation":{

13

14 },

15 "expiresIn":109,

16 "expired":false

17 }

Once the access token is generated, we are ready to pass it along with every subsequent requests for the
protected resources on the server.

http://localhost:8080/SecureRESTWithOAuth/api/Employee/abhimanyu?access_token=7792b077-7ae0-
427e-8170-8b1440e5fefd
Introduction to Spring Boot
WebJars
1. Introduction
Among the other features that Spring Boot simplifies, one of them is the webjars. Webjars are the static
client-side dependencies (for eg. javascript libraries) packaged into JARs. Manually adding the client
side libraries could be difficult to maintain, so with webjars (feature enhanced in Spring Boot), we can
add these libraries just by making required pom configuration entries, and we are all-set to start using
them instantly.

Webjars works with commonly used build tools like Maven and Gradle and makes it very easy to
manage and maintain.
2. How it works?
This means that just with the below specification in pom.xml file, the Bootstrap and jQuery becomes
ready for us to use it in our HTML page or any of the view technology we are using.
1 <!-- webjars -->

2 <dependency>

3 <groupId>org.webjars</groupId>

4 <artifactId>bootstrap</artifactId>

5 <version>3.3.7-1</version>

6 </dependency>

7 <dependency>

8 <groupId>org.webjars</groupId>

9 <artifactId>jquery</artifactId>

10 <version>3.1.1</version>

11 </dependency>

We can now directly use the client-side libraries in our view pages like –

1 <script src="/webjars/jquery/3.1.1/jquery.min.js"></script>

2 <script src="/webjars/bootstrap/3.3.7-1/js/bootstrap.min.js"></script>

3 <link rel="stylesheet"
4 href="/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css" />

5 </head>

Spring Boot automatically configures Spring to map requests for /webjars to the /META-
INF/resources/webjars directory of all the JARs in the CLASSPATH.
Things can also work out even without specifying the WebJar (client-side library) versions while
including them in HTML view files, like we mentioned in the previous snippet. For this to work, we
need to additionally insert the below mentioned webjar-locator dependency into the pom file.
1 <!-- webjars-locator -->

2 <dependency>

3 <groupId>org.webjars</groupId>

4 <artifactId>webjars-locator</artifactId>

5 <version>0.30</version>

6 </dependency>

Spring Boot automatically detects the webjars-locator library in the classpath and uses it to
automatically resolve the version of WebJars we are trying to insert into our HTML page.

Reference Link
https://www.webjars.org/documentation#springboot

Das könnte Ihnen auch gefallen