前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring boot with Oauth2

Spring boot with Oauth2

作者头像
netkiller old
发布2018-03-05 18:46:21
1.7K0
发布2018-03-05 18:46:21
举报
文章被收录于专栏:NetkillerNetkiller

本文节选自《Netkiller Java 手札》

作者:netkiller 网站:http://www.netkiller.cn

5.20. Spring boot with Oauth2

下面例子由三个项目组成,分别是 tools, server, client。

其中 tools 是密码生成工具

5.20.1. Maven

代码语言:javascript
复制
<?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>cn.netkiller</groupId>
	<artifactId>oauth</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>pom</packaging>

	<name>oauth</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.6.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- Security -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.security.oauth</groupId>
			<artifactId>spring-security-oauth2</artifactId>
		</dependency>

	</dependencies>
	<modules>
		<module>server</module>
		<module>client</module>
	</modules>
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build></project>

5.20.2. Password tools

Maven

代码语言:javascript
复制
<?xml version="1.0"?><project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>cn.netkiller</groupId>
    <artifactId>oauth</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <artifactId>tools</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>tools</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies></project>

下面的代码用于生成 Spring security 所用的密码

代码语言:javascript
复制
package cn.netkiller.oauth.tools;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;/**
 * Hello world!
 *
 */public class App {	public static void main(String[] args) {		int i = 0;		while (i < 10) {
			String password = "123456";
			BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
			String hashedPassword = passwordEncoder.encode(password);

			System.out.println(hashedPassword);
			i++;
		}
	}
}

运行后生成类似的密码

代码语言:javascript
复制
$2a$10$IrDG5Yr3CGorEg9gKG8smeRLnNUieCVyBCJHA80U6h20HDFCxd43W$2a$10$wseh5xFv1L3a3uHQId0MAOqAN0rKKcuX.RDaBPQ.pV/hsr80TqwxO$2a$10$xP3Gc/5/PN03BdkDfhUjAemTRVaiwr0lsaqPqD18UI.ho9nRC/ebW$2a$10$S.wLZ6e5YvmQA6mkX8yXWOdJbvahtDOesRu0ZwPOzAPCwpo7eDAsi$2a$10$Jo/yuWyiAZ2Lj8.ywoPl7OeOJYuP7RVq8l.qc/zOwtW8MTFp3NYGO$2a$10$eEvvjPok0fRK.DU6yF0qI.aucuiWr3y5G93SLq9/76ovcOwIuQAuS$2a$10$BWEkANxbgwATNQCEI9/uNevNEUNlomGY7cZ2CQVm.qCRcnyukT.Si$2a$10$69wSpyJQvjzJY7ou5PFWlOlEIecQukHV9WEq0nebsz5V6IZKfOVv2$2a$10$Cyj3hM39V34r5pMeQ.Y9peuUqYMBSvsJ7GTBgp4.stWaTtWMboYGS$2a$10$0/o4cRN2.tmnc58sH.N4WOsreVI6sWlPl4CCBrmUfJ332TMfRzA42

5.20.3. Server

5.20.3.1. Maven
代码语言:javascript
复制
<?xml version="1.0"?><project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>cn.netkiller</groupId>
		<artifactId>oauth</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<groupId>cn.netkiller</groupId>
	<artifactId>server</artifactId>
	<name>server</name>
	<description>Example Spring Boot REST project</description>

	<url>http://maven.apache.org</url>
	<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>

	</dependencies></project>
5.20.3.2. application.properties
代码语言:javascript
复制
server.port=8000server.contextPath=/api

logging.level.com.gigy=DEBUG

# Data source properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/5kwords?useSSL=falsespring.datasource.username=5kwords
spring.datasource.password=5kwords
spring.datasource.max-idle=10spring.datasource.max-wait=10000spring.datasource.min-idle=5spring.datasource.initial-size=5spring.datasource.validation-query=SELECT 1spring.datasource.test-on-borrow=falsespring.datasource.test-while-idle=truespring.datasource.time-between-eviction-runs-millis=18800spring.datasource.jdbc-interceptors=ConnectionState;SlowQueryReport(threshold=0)

spring.jpa.database=MYSQL
spring.jpa.show-sql=true#spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.ddl-auto=create-drop
#spring.jpa.hibernate.ddl-auto=validate
#spring.jpa.show-sql=true
5.20.3.3. EnableAuthorizationServer
代码语言:javascript
复制
package cn.netkiller.oauth.server.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.core.userdetails.UserDetailsService;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;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.configuration.EnableAuthorizationServer;import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;

@Configuration@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {

	@Autowired
	@Qualifier("userDetailsService")
	private UserDetailsService userDetailsService;

	@Autowired
	private AuthenticationManager authenticationManager;

	@Value("${oauth.tokenTimeout:3600}")	private int expiration;

	@Bean
	public PasswordEncoder passwordEncoder() {		return new BCryptPasswordEncoder();
	}

	@Override
	public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {		configurer.authenticationManager(authenticationManager);		configurer.userDetailsService(userDetailsService);
	}

	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {		clients.inMemory().withClient("api").secret("secret").accessTokenValiditySeconds(expiration).scopes("read", "write").authorizedGrantTypes("password", "refresh_token").resourceIds("resource");
	}

}
5.20.3.4. EnableResourceServer
代码语言:javascript
复制
package cn.netkiller.oauth.server.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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.oauth2.config.annotation.web.configuration.EnableResourceServer;@Configuration@EnableWebSecurity@EnableResourceServer@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {	/**
	 * Constructor disables the default security settings
	 */
	public WebSecurityConfiguration() {
		super(true);
	}	@Override
	public void configure(WebSecurity web) throws Exception {
		web.ignoring().antMatchers("/login");
	}	@Override
	public void configure(HttpSecurity http) throws Exception {
		http.antMatcher("/api/**").authorizeRequests().anyRequest().authenticated();
	}	@Bean
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}
}
5.20.3.5. Entity Table
代码语言:javascript
复制
package cn.netkiller.oauth.server.model;import java.util.ArrayList;import java.util.Collection;import java.util.List;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.Table;import org.springframework.security.core.GrantedAuthority;import org.springframework.security.core.userdetails.UserDetails;@Entity@Table(name = "users")public class User implements UserDetails {	
	static final long serialVersionUID = 1L;	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)	@Column(name = "user_id", nullable = false, updatable = false)	private Long id;	
	@Column(name = "username", nullable = false, unique = true)	private String username;	
	@Column(name = "password", nullable = false)	private String password;	
	@Column(name = "enabled", nullable = false)	private boolean enabled;	public Collection<? extends GrantedAuthority> getAuthorities() {
		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();		
		return authorities;
	}	public boolean isAccountNonExpired() {		return true;
	}	public boolean isAccountNonLocked() {		// we never lock accounts
		return true;
	}	public boolean isCredentialsNonExpired() {		// credentials never expire
		return true;
	}	public boolean isEnabled() {		return enabled;
	}	public String getPassword() {		return password;
	}	public String getUsername() {		return username;
	}

}
5.20.3.6. UserRepository
代码语言:javascript
复制
package cn.netkiller.oauth.server.repository;import org.springframework.data.jpa.repository.JpaRepository;import cn.netkiller.oauth.server.model.User;public interface UserRepository extends JpaRepository<User, Long> {	/**
	 * Find a user by username
	 *
	 * @param username
	 *            the user's username
	 * @return user which contains the user with the given username or null.
	 */
	User findOneByUsername(String username);

}
5.20.3.7. UserService
代码语言:javascript
复制
package cn.netkiller.oauth.server.service;import org.springframework.beans.factory.annotation.Autowired;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 cn.netkiller.oauth.server.repository.UserRepository;@Service("userDetailsService")public class UserService implements UserDetailsService {	@Autowired
	private UserRepository userRepository;	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {		return userRepository.findOneByUsername(username);
	}
}
5.20.3.8. TestRestController
代码语言:javascript
复制
package cn.netkiller.oauth.server.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;@RestController@RequestMapping("/test")
public class TestRestController {	@RequestMapping(value = "hello", method = RequestMethod.GET)
	public ResponseEntity<String> hello() {
		return new ResponseEntity<String>("Hello world !", HttpStatus.OK);
	}	@PreAuthorize("#oauth2.hasScope('write')")	@RequestMapping(value = "set/{string}", method = RequestMethod.GET)
	public ResponseEntity<String> set(String string) {
		return new ResponseEntity<String>(string, HttpStatus.OK);
	}
}
5.20.3.9. 数据库初始化

在 src/main/resources 目录创建 data.sql 文件

代码语言:javascript
复制
INSERT INTO users (user_id, username, password, enabled) VALUES 
	('1', 'netkiller@msn.com', '$2a$10$Cyj3hM39V34r5pMeQ.Y9peuUqYMBSvsJ7GTBgp4.stWaTtWMboYGS', true);

此处密码 $2a$10$Cyj3hM39V34r5pMeQ.Y9peuUqYMBSvsJ7GTBgp4.stWaTtWMboYGS 请使用上面提供的工具生成。

5.20.3.10. Test

启动 Spring boot Server 项目

代码语言:javascript
复制
mvn spring-boot:run

启动后 Spring boot 会导入 data.sql 文件

代码语言:javascript
复制
mysql> select * from users where username="netkiller@msn.com";
+---------+---------+--------------------------------------------------------------+-------------------+| user_id | enabled | password                                                     | username          |
+---------+---------+--------------------------------------------------------------+-------------------+
|       4 |        | $2a$10$Cyj3hM39V34r5pMeQ.Y9peuUqYMBSvsJ7GTBgp4.stWaTtWMboYGS | netkiller@msn.com |+---------+---------+--------------------------------------------------------------+-------------------+1 row in set (0.00 sec)
代码语言:javascript
复制
MacBook-Pro:Application neo$ curl -X POST --user 'api:secret' -d 'grant_type=password&username=netkiller@msn.com&password=123456' http://localhost:8000/api/oauth/token{"access_token":"5bc0ee89-cd6d-47be-b31f-89c9e028159b","token_type":"bearer","refresh_token":"5107c09b-de85-4faf-8396-941572cf30d2","expires_in":3599,"scope":"read write"}MacBook-Pro:Application neo$ MacBook-Pro:Application neo$ curl -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: Bearer 5bc0ee89-cd6d-47be-b31f-89c9e028159b" -X GET http://localhost:8000/api/test/helloHello world !
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Netkiller 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 本文节选自《Netkiller Java 手札》
  • 5.20. Spring boot with Oauth2
    • 5.20.1. Maven
      • 5.20.2. Password tools
        • 5.20.3. Server
          • 5.20.3.1. Maven
          • 5.20.3.2. application.properties
          • 5.20.3.3. EnableAuthorizationServer
          • 5.20.3.4. EnableResourceServer
          • 5.20.3.5. Entity Table
          • 5.20.3.6. UserRepository
          • 5.20.3.7. UserService
          • 5.20.3.8. TestRestController
          • 5.20.3.9. 数据库初始化
          • 5.20.3.10. Test
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档