- 演示工具版本
- 项目结构
- Spring Boot 默认的验证方式
- Maven 文件
- application.properties
- MySQL 表和 JAVA 实体
- 创建 DAO 用于用户认证
- 实现 UserDetailsService
- 实现 BasicAuthenticationEntryPoint
- Security 配置
- 创建 DAO 用于 CRUD 操作
- 创建带安全验证 CURD 操作的 Service
- 创建 Controller 用于 CURD 操作
- 使用 SpringApplication 创建主类
- 使用 RestTemplate 创建客户端
- 运行应用程序
- 1. 使用Eclipse
- 2. 使用Maven命令
- 3. 使用可执行的JAR
- 参考文献
- 源码下载
本页将介绍Spring Boot Security REST + JPA + Hibernate + MySQL CRUD的例子。
当我们使用Spring Boot创建应用程序时,我们只需写几行代码就可以包含网络请求、安全验证和数据库连接等功能。
如果Spring Boot在类路径中获得Spring Security,那么它将自动执行与安全有关的配置。
同样,如果Spring Boot在其类路径中获得Spring Web和Spring Data,那么Spring Boot会自动执行Spring Web和数据库连接相关的配置。
在Spring Security方面,Spring Boot默认配置了内存中的认证,使用一个用户和随机密码,在每次服务器重启后都会改变。我们可以在控制台中获得默认密码。
在我们的例子中,我们将在数据库中保存用户认证相关的数据,所以我们必须覆盖Spring Boot的默认安全配置。我们将创建一个带有@Configuration和@EnableWebSecurity注释的安全配置文件。
为了覆盖HttpSecurity,我们的安全配置类需要扩展WebSecurityConfigurerAdapter类并覆盖configure()方法。
为了启用方法级别的安全,用@EnableGlobalMethodSecurity来注释安全配置类。
为了使用数据库对用户进行认证和授权,我们需要实现UserDetailsService接口。
我们将在我们的REST网络服务例子中处理创建(CREATE)、读取(READ)、更新(UPDATe)和删除(DELETE)操作,简称CRUD。
让我们一步一步地讨论这个完整的例子。
演示工具版本- Java 8
- Spring Boot 1.5.3.RELEASE
- Maven 3.3
- MySQL 5.5
- Eclipse Mars
如果spring security在类路径中,那么我们的spring boot web应用程序默认会自动使用基本认证来保证安全。
一个默认的用户名 "user "和随机密码将在服务器启动时显示在控制台中,可用于登录验证。
密码在控制台显示如下。
Using default security password: 7e9850aa-d985-471a-bae1-25d741d4da23
上述密码是随机的,并且在服务器重启时改变。默认情况下,spring使用内存认证,单用户命名为 “user”。找到这些配置。
1. 要在spring boot应用程序中启用spring security,只需在maven或gradle文件中使用以下spring-boot配置。
spring-boot-starter-security
2. 为了改变默认密码,spring boot提供了security.user.password属性,需要在application.properties中进行配置,如下所示。
security.user.password= concretepage
现在我们可以使用user/concretepage的凭证登录应用程序。其他安全属性也可以通过SecurityProperties在application.properties中使用security.*前缀来改变,如下所示。
security.basic.enabled: 启用基本认证。默认值为true。
security.basic.path: 配置需要安全验证的路径。我们需要提供逗号分隔的路径。
security.enable-csrf: 启用和禁用CSRF。默认值为false。
security.require-ssl: 启用和禁用SSL。默认值为false。
security.sessions: 默认值是无状态。值可以是总是(always)、从不(never)、如果需要(if_required)、无状态(stateless)。
security.user.name: 配置用户名。默认用户是user。
security.user.password: 配置密码。
security.user.role: 它配置了角色。默认的角色是USER。
3. 如果我们已经微调了我们的日志配置,那么为了打印默认的随机密码,我们需要在application.properties中配置以下属性,级别为INFO。
logging.level.org.springframework.boot.autoconfigure.security= INFO
4. 默认情况下,静态路径是不做安全验证的,如/cssfavicon.ico。
5. 如HSTS、XSS、CSRF、缓存等功能在spring security中是默认提供的。
上述属性可以使用security.*来打开和关闭,但如果我们想在数据库中使用用户名和密码,那么我们需要使用UserDetailsService。
为了控制安全相关的配置,我们可以创建一个安全配置类,它将扩展WebSecurityConfigurerAdapter,然后覆盖configure()方法。这个类将被注解为@Configuration和@EnableWebSecurity。
如果我们想启用方法级别的安全,该类将被注解为@EnableGlobalMethodSecurity。
Maven 文件pom.xml
4.0.0 com.concretepage spring-boot-demo 0.0.1-SNAPSHOT jar spring-demo Spring Boot Demo Project org.springframework.boot spring-boot-starter-parent 1.5.3.RELEASE 1.8 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-data-jpa mysql mysql-connector-java org.springframework.boot spring-boot-devtools true org.springframework.boot spring-boot-maven-plugin
当Spring Boot应用程序在类路径中找到任何JAR,那么Spring Boot会自动配置所需的设置。
spring-boot-starter-web: 自动配置web应用程序设置。
spring-boot-starter-security: 自动配置安全相关设置。
spring-boot-starter-data-jpa: 自动配置与数据库连接相关的设置。
application.properties在Spring Boot中,要配置数据库相关属性、hibernate和日志,我们需要使用application.properties或application.yml。这些文件会被Spring Boot自动读取。
application.properties
#spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/concretepage spring.datasource.username=root spring.datasource.password= spring.datasource.tomcat.max-wait=20000 spring.datasource.tomcat.max-active=50 spring.datasource.tomcat.max-idle=20 spring.datasource.tomcat.min-idle=15 spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect spring.jpa.properties.hibernate.id.new_generator_mappings = false spring.jpa.properties.hibernate.format_sql = true logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE #Security Configuration--- #security.user.password= concretepage #prints default password--- #logging.level.org.springframework.boot.autoconfigure.security= INFO
使用spring.datasource.*来配置数据源相关属性。使用spring.jpa.properties.*来配置JPA相关属性。
在我们的例子中,我们正在使用JPA和hibernate。
MySQL 表和 JAVA 实体Database Schema
CREATE DATAbase IF NOT EXISTS `concretepage` ;
USE `concretepage`;
-- Dumping structure for table concretepage.articles
CREATE TABLE IF NOT EXISTS `articles` (
`article_id` int(5) NOT NULL AUTO_INCREMENT,
`title` varchar(200) NOT NULL,
`category` varchar(100) NOT NULL,
PRIMARY KEY (`article_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.articles: ~3 rows (approximately)
INSERT INTO `articles` (`article_id`, `title`, `category`) VALUES
(1, 'Java Concurrency', 'Java'),
(2, 'Hibernate HQL ', 'Hibernate'),
(3, 'Spring MVC with Hibernate', 'Spring');
-- Dumping structure for table concretepage.users
CREATE TABLE IF NOT EXISTS `users` (
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
`full_name` varchar(100) NOT NULL,
`role` varchar(50) NOT NULL,
`country` varchar(100) NOT NULL,
`enabled` tinyint(1) NOT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Dumping data for table concretepage.users: ~2 rows (approximately)
INSERT INTO `users` (`username`, `password`, `full_name`, `role`, `country`, `enabled`) VALUES
('mukesh', '$2a$10$N0eqNiuikWCy9ETQ1rdau.XEELcyEO7kukkfoiNISk/9F7gw6eB0W', 'Mukesh Sharma', 'ROLE_ADMIN', 'India', 1),
('tarun', '$2a$10$QifQnP.XqXDW0Lc4hSqEg.GhTqZHoN2Y52/hoWr4I5ePxK7D2Pi8q', 'Tarun Singh', 'ROLE_USER', 'India', 1);
我们有两个表users和articles。
在users表中,我们保存与用户有关的信息,在articles表中,我们保存与文章有关的信息。
我们正在使用BCrypt密码编码方案。
找到一个简单的主类,可以用来生成BCrypt密码。
Main.java
package com.concretepage;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class Main {
public static void main(String[] args) {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
System.out.println(encoder.encode("m123"));
}
}
对于上述数据库模式中给定的两个表,请找到java实体。
UserInfo.java
package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="users")
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="username")
private String userName;
@Column(name="password")
private String password;
@Column(name="role")
private String role;
@Column(name="full_name")
private String fullName;
@Column(name="country")
private String country;
@Column(name="enabled")
private short enabled;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public short getEnabled() {
return enabled;
}
public void setEnabled(short enabled) {
this.enabled = enabled;
}
}
Article.java
package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="articles")
public class Article implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="article_id")
private int articleId;
@Column(name="title")
private String title;
@Column(name="category")
private String category;
public int getArticleId() {
return articleId;
}
public void setArticleId(int articleId) {
this.articleId = articleId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}
创建 DAO 用于用户认证
在我们的例子中,我们没有使用Spring Boot默认的内存认证。我们将在MySQL数据库中存储用户认证相关的信息,并使用Hibernate访问它们。所以我们要创建一个DAO方法来返回给定用户名的用户信息。
IUserInfoDAO.java
package com.concretepage.dao;
import com.concretepage.entity.UserInfo;
public interface IUserInfoDAO {
UserInfo getActiveUser(String userName);
}
UserInfoDAO.java
package com.concretepage.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.UserInfo;
@Repository
@Transactional
public class UserInfoDAO implements IUserInfoDAO {
@PersistenceContext
private EntityManager entityManager;
public UserInfo getActiveUser(String userName) {
UserInfo activeUserInfo = new UserInfo();
short enabled = 1;
List> list = entityManager.createQuery("SELECT u FROM UserInfo u WHERe userName=? and enabled=?")
.setParameter(1, userName).setParameter(2, enabled).getResultList();
if(!list.isEmpty()) {
activeUserInfo = (UserInfo)list.get(0);
}
return activeUserInfo;
}
}
Spring @Transactional注解的作用是使DAO方法具有事务性。
我们使用JPA的API来处理数据库事务,因此我们将使用依赖注入来实例化EntityManager。
为了实现这一点,我们创建了带有@PersistenceContext注解的EntityManager属性。
实现 UserDetailsServiceSpring提供了UserDetailsService来验证和授权用户。它从我们的DAO接收用户相关的数据。
MyAppUserDetailsService.java
package com.concretepage.config;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.concretepage.dao.IUserInfoDAO;
import com.concretepage.entity.UserInfo;
@Service
public class MyAppUserDetailsService implements UserDetailsService {
@Autowired
private IUserInfoDAO userInfoDAO;
@Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException {
UserInfo activeUserInfo = userInfoDAO.getActiveUser(userName);
GrantedAuthority authority = new SimpleGrantedAuthority(activeUserInfo.getRole());
UserDetails userDetails = (UserDetails)new User(activeUserInfo.getUserName(),
activeUserInfo.getPassword(), Arrays.asList(authority));
return userDetails;
}
}
实现 BasicAuthenticationEntryPoint
在我们的例子中,我们使用的是基于header的认证。
当我们不使用基于登录页面的认证时,对于任何对应用程序的请求,Spring需要发送一个带有适当状态代码的错误。
Spring提供了BasicAuthenticationEntryPoint,需要实现它来实现。
它有一个方法commence(),我们将覆盖该方法并返回一个状态代码(401),未授权的状态代码包含认证所需的认证类型的头。
在我们的例子中,我们使用的是基本认证。
AppAuthenticationEntryPoint.java
package com.concretepage.config;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@Component
public class AppAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.addHeader("WWW-Authenticate", "Basic realm="" + getRealmName() + """);
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
}
@Override
public void afterPropertiesSet() throws Exception {
setRealmName("MY APP REALM");
}
}
Security 配置
现在我们将创建安全配置文件。
SecurityConfig.java
package com.concretepage.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.method.configuration.EnableGlobalMethodSecurity;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAppUserDetailsService myAppUserDetailsService;
@Autowired
private AppAuthenticationEntryPoint appAuthenticationEntryPoint;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/user/**").hasAnyRole("ADMIN","USER")
.and().httpBasic().realmName("MY APP REALM")
.authenticationEntryPoint(appAuthenticationEntryPoint);
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
auth.userDetailsService(myAppUserDetailsService).passwordEncoder(passwordEncoder);
}
}
该类已被注解为@EnableWebSecurity,它从WebSecurityConfigurer类中配置了spring security。
如果我们想覆盖WebSecurityConfigurer的任何方法,那么我们要扩展WebSecurityConfigurerAdapter。
在我们的例子中,为了配置HttpSecurity,我们已经覆盖了configure()方法。
在这里,我们已经授权了一个带有/user/**模式的网址。
我们还将在这里配置BasicAuthenticationEntryPoint的实现类。
现在,autowire方法configureGlobal()中,我们用BCryptPasswordEncoder编码方案配置了UserDetailsService的实现类。
为了保护服务方法,我们需要使用@EnableGlobalMethodSecurity注解。
要使用@Secured注解启用方法级别的安全,配置securedEnabled元数据,数值为true。
要启用@PreAuthorize和@PostAuthorize注解,请将prePostEnabled元数据配置为true。
创建 DAO 用于 CRUD 操作使用JPA EntityManager用于CRUD操作的DAO类。
IArticleDAO.java
package com.concretepage.dao;
import java.util.List;
import com.concretepage.entity.Article;
public interface IArticleDAO {
List getAllArticles();
Article getArticleById(int articleId);
void addArticle(Article article);
void updateArticle(Article article);
void deleteArticle(int articleId);
boolean articleExists(String title, String category);
}
ArticleDAO.java
package com.concretepage.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.Article;
@Transactional
@Repository
public class ArticleDAO implements IArticleDAO {
@PersistenceContext
private EntityManager entityManager;
@Override
public Article getArticleById(int articleId) {
return entityManager.find(Article.class, articleId);
}
@SuppressWarnings("unchecked")
@Override
public List getAllArticles() {
String hql = "FROM Article as atcl ORDER BY atcl.articleId";
return (List) entityManager.createQuery(hql).getResultList();
}
@Override
public void addArticle(Article article) {
entityManager.persist(article);
}
@Override
public void updateArticle(Article article) {
Article artcl = getArticleById(article.getArticleId());
artcl.setTitle(article.getTitle());
artcl.setCategory(article.getCategory());
entityManager.flush();
}
@Override
public void deleteArticle(int articleId) {
entityManager.remove(getArticleById(articleId));
}
@Override
public boolean articleExists(String title, String category) {
String hql = "FROM Article as atcl WHERe atcl.title = ? and atcl.category = ?";
int count = entityManager.createQuery(hql).setParameter(1, title)
.setParameter(2, category).getResultList().size();
return count > 0 ? true : false;
}
}
创建带安全验证 CURD 操作的 Service
现在,我们将为CRUD操作创建具有安全验证的服务方法。
IArticleService.java
package com.concretepage.service;
import java.util.List;
import org.springframework.security.access.annotation.Secured;
import com.concretepage.entity.Article;
public interface IArticleService {
@Secured ({"ROLE_ADMIN", "ROLE_USER"})
List getAllArticles();
@Secured ({"ROLE_ADMIN", "ROLE_USER"})
Article getArticleById(int articleId);
@Secured ({"ROLE_ADMIN"})
boolean addArticle(Article article);
@Secured ({"ROLE_ADMIN"})
void updateArticle(Article article);
@Secured ({"ROLE_ADMIN"})
void deleteArticle(int articleId);
}
角色为ADMIN的用户可以访问所有的方法。角色为USER的用户只能访问getAllArticle()和getArticleById()服务方法。
现在找到实现类。
ArticleService.java
package com.concretepage.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.dao.IArticleDAO;
import com.concretepage.entity.Article;
@Service
public class ArticleService implements IArticleService {
@Autowired
private IArticleDAO articleDAO;
@Override
public Article getArticleById(int articleId) {
Article obj = articleDAO.getArticleById(articleId);
return obj;
}
@Override
public List getAllArticles(){
return articleDAO.getAllArticles();
}
@Override
public synchronized boolean addArticle(Article article){
if (articleDAO.articleExists(article.getTitle(), article.getCategory())) {
return false;
} else {
articleDAO.addArticle(article);
return true;
}
}
@Override
public void updateArticle(Article article) {
articleDAO.updateArticle(article);
}
@Override
public void deleteArticle(int articleId) {
articleDAO.deleteArticle(articleId);
}
}
创建 Controller 用于 CURD 操作
找到拥有CREATE、READ、UPDATE和DELETE(CRUD)操作方法的控制器类。
ArticleController.java
package com.concretepage.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.util.UriComponentsBuilder;
import com.concretepage.entity.Article;
import com.concretepage.service.IArticleService;
@Controller
@RequestMapping("user")
public class ArticleController {
@Autowired
private IArticleService articleService;
@GetMapping("article/{id}")
public ResponseEntity getArticleById(@PathVariable("id") Integer id) {
Article article = articleService.getArticleById(id);
return new ResponseEntity(article, HttpStatus.OK);
}
@GetMapping("articles")
public ResponseEntity> getAllArticles() {
List list = articleService.getAllArticles();
return new ResponseEntity>(list, HttpStatus.OK);
}
@PostMapping("article")
public ResponseEntity addArticle(@RequestBody Article article, UriComponentsBuilder builder) {
boolean flag = articleService.addArticle(article);
if (flag == false) {
return new ResponseEntity(HttpStatus.CONFLICT);
}
HttpHeaders headers = new HttpHeaders();
headers.setLocation(builder.path("/article/{id}").buildAndExpand(article.getArticleId()).toUri());
return new ResponseEntity(headers, HttpStatus.CREATED);
}
@PutMapping("article")
public ResponseEntity updateArticle(@RequestBody Article article) {
articleService.updateArticle(article);
return new ResponseEntity(article, HttpStatus.OK);
}
@DeleteMapping("article/{id}")
public ResponseEntity deleteArticle(@PathVariable("id") Integer id) {
articleService.deleteArticle(id);
return new ResponseEntity(HttpStatus.NO_CONTENT);
}
}
从spring 4.3开始,我们有了请求映射注解,如
@GetMapping :HTTP GET方法
@PostMapping : HTTP POST方法
@PutMapping :HTTP PUT方法
@DeleteMapping :HTTP DELETE方法
我们为CRUD操作创建了以下网址。
1. Create :
方法: POST, 网址: /user/article
2. Read :
方法: GET, 网址: /user/article/{id}
方法: GET, 网址: /user/articles
3. Update :
方法: PUT, 网址: /user/article
4. Delete :
方法: DELETE, 网址: /user/article/{id}
创建一个带有main()方法的类,它将调用SpringApplication.run()来运行应用程序。
首先下载所有的JAR依赖项,然后编译项目,然后启动嵌入式tomcat服务器。
MyApplication.java
package com.concretepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
我们需要用@SpringBootApplication注解来注解这个类,它相当于@Configuration、@EnableAutoConfiguration和@ComponentScan注解。
使用 RestTemplate 创建客户端为了消费REST网络服务,我们使用RestTemplate。对于认证,我们将在HttpHeaders中传递base64编码的凭证,作为username:password令牌,并进行基本授权。
RestClientUtil.java
package com.concretepage.client;
import java.net.URI;
import org.apache.tomcat.util.codec.binary.base64;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.concretepage.entity.Article;
public class RestClientUtil {
private HttpHeaders getHeaders() {
String credential="mukesh:m123";
//String credential="tarun:t123";
String encodedCredential = new String(base64.encodebase64(credential.getBytes()));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Basic " + encodedCredential);
return headers;
}
public void getArticleByIdDemo() {
HttpHeaders headers = getHeaders();
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/user/article/{id}";
HttpEntity requestEntity = new HttpEntity(headers);
ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article.class, 1);
Article article = responseEntity.getBody();
System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle()
+", Category:"+article.getCategory());
}
public void getAllArticlesDemo() {
HttpHeaders headers = getHeaders();
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/user/articles";
HttpEntity requestEntity = new HttpEntity(headers);
ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Article[].class);
Article[] articles = responseEntity.getBody();
for(Article article : articles) {
System.out.println("Id:"+article.getArticleId()+", Title:"+article.getTitle()
+", Category: "+article.getCategory());
}
}
public void addArticleDemo() {
HttpHeaders headers = getHeaders();
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/user/article";
Article objArticle = new Article();
objArticle.setTitle("Spring REST Security using Hibernate");
objArticle.setCategory("Spring");
HttpEntity requestEntity = new HttpEntity(objArticle, headers);
URI uri = restTemplate.postForLocation(url, requestEntity);
System.out.println(uri.getPath());
}
public void updateArticleDemo() {
HttpHeaders headers = getHeaders();
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/user/article";
Article objArticle = new Article();
objArticle.setArticleId(1);
objArticle.setTitle("Update:Java Concurrency");
objArticle.setCategory("Java");
HttpEntity requestEntity = new HttpEntity(objArticle, headers);
restTemplate.put(url, requestEntity);
}
public void deleteArticleDemo() {
HttpHeaders headers = getHeaders();
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:8080/user/article/{id}";
HttpEntity requestEntity = new HttpEntity(headers);
restTemplate.exchange(url, HttpMethod.DELETE, requestEntity, Void.class, 4);
}
public static void main(String args[]) {
RestClientUtil util = new RestClientUtil();
//util.getArticleByIdDemo();
util.getAllArticlesDemo();
//util.addArticleDemo();
util.updateArticleDemo();
//util.deleteArticleDemo();
}
}
在这里,我们正在执行创建、读取、更新和删除(CRUD)操作。我们可以使用具有ADMIN角色的mukesh/m123和具有USER角色的tarun/t123凭证来测试该应用程序。
运行应用程序要运行该应用程序,首先在MySQL中创建表,如例子中给出的。现在我们可以通过以下方式运行REST网络服务。
1. 使用Eclipse使用页面末尾的下载链接下载项目的源代码。
将该项目导入eclipse。
使用命令提示符,进入项目的根文件夹并运行。
mvn clean eclipse:eclipse
然后在eclipse中刷新该项目。点击Run as -> Java Application来运行主类MyApplication。
Tomcat服务器将被启动。
2. 使用Maven命令下载项目的源代码。使用命令提示符进入项目的根文件夹并运行命令。
mvn spring-boot:run
Tomcat服务器将被启动。
3. 使用可执行的JAR使用命令提示符,转到项目的根文件夹并运行该命令。
mvn clean package
我们将在目标文件夹中得到可执行的spring-boot-demo-0.0.1-SNAPSHOT.jar。以下列方式运行这个JAR。
java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar
Tomcat服务器将被启动。
现在我们已经准备好测试这个应用程序了。要运行客户端,在eclipse中进入RestClientUtil类,点击Run as -> Java Application。
我们也可以使用Postman测试应用程序。
如图所示。
【1】Spring Boot Security Features
【2】Spring Boot REST + JPA + Hibernate + MySQL Example
【3】Spring Boot Security REST + JPA + Hibernate + MySQL CRUD Example
提取码:mao4
spring-boot-security-rest-jpa-hibernate-mysql-crud-example.zip



