All Projects → dzinot → Spring Boot 2 Oauth2 Authorization Jwt

dzinot / Spring Boot 2 Oauth2 Authorization Jwt

Licence: mit
Spring Boot 2 OAuth2 JWT Authorization server implementation with Database for Users and Clients (JPA, Hibernate, MySQL)

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to Spring Boot 2 Oauth2 Authorization Jwt

Spring Boot Mysql Rest Api Tutorial
Building a Restful CRUD API using Spring Boot, Mysql, JPA and Hibernate
Stars: ✭ 279 (+142.61%)
Mutual labels:  hibernate, jpa, mysql, spring
Hunt Entity
An object-relational mapping (ORM) framework for D language (Similar to JPA / Doctrine), support PostgreSQL and MySQL.
Stars: ✭ 51 (-55.65%)
Mutual labels:  hibernate, jpa, database, mysql
Jooq
jOOQ is the best way to write SQL in Java
Stars: ✭ 4,695 (+3982.61%)
Mutual labels:  hibernate, jpa, database, mysql
Xboot
基于Spring Boot 2.x的一站式前后端分离快速开发平台XBoot 微信小程序+Uniapp 前端:Vue+iView Admin 后端:Spring Boot 2.x/Spring Security/JWT/JPA+Mybatis-Plus/Redis/Elasticsearch/Activiti 分布式限流/同步锁/验证码/SnowFlake雪花算法ID 动态权限 数据权限 工作流 代码生成 定时任务 社交账号 短信登录 单点登录 OAuth2开放平台 客服机器人 数据大屏 暗黑模式
Stars: ✭ 3,432 (+2884.35%)
Mutual labels:  jpa, mysql, jwt, oauth2
Spring Framework Petclinic
A Spring Framework application based on JSP, Spring MVC, Spring Data JPA, Hibernate and JDBC
Stars: ✭ 251 (+118.26%)
Mutual labels:  hibernate, jpa, mysql, spring
Koa Vue Notes Api
🤓 This is a simple SPA built using Koa as the backend, Vue as the first frontend, and React as the second frontend. Features MySQL integration, user authentication, CRUD note actions, and async/await.
Stars: ✭ 342 (+197.39%)
Mutual labels:  database, mysql, jwt
Dokit
基于 Spring Boot2、 Jpa、 Spring Security、JWT、redis、Vue的前后端分离的后台管理系统开发平台, 用户管理、菜单管理、角色管理、字典管理、权限控制的方式为RBAC,操作日志、异常日志、接口限流、项目支持数据权限管理,支持一键生成前后端代码(支持在线预览及打包下载),支持前端菜单动态路由 可一键部署服务器应用,数据库。系统中活跃用户状态监控,监视当前系统CPU、内存、磁盘、堆栈等相关信息,基于Element UI在线表单设计及生成Vue代码。
Stars: ✭ 348 (+202.61%)
Mutual labels:  jpa, mysql, jwt
Hibernate Orm
Hibernate's core Object/Relational Mapping functionality
Stars: ✭ 4,806 (+4079.13%)
Mutual labels:  hibernate, jpa, database
Go Book Store Api
Go Sample project to understand Mysql CRUD operation with best practises Includes logging, JWT, Swagger and Transactions
Stars: ✭ 18 (-84.35%)
Mutual labels:  database, mysql, jwt
Books Recommendation
程序员进阶书籍(视频),持续更新(Programmer Books)
Stars: ✭ 558 (+385.22%)
Mutual labels:  mysql, spring, oauth2
Springbootunity
rabbitmq、redis、scheduled、socket、mongodb、Swagger2、spring data jpa、Thymeleaf、freemarker etc. (muti module spring boot project) (with spring boot framework,different bussiness scence with different technology。)
Stars: ✭ 845 (+634.78%)
Mutual labels:  hibernate, mysql, spring
Ee7 Jaxrs Sample
Building RESTful APIs with Java EE 7 and JAXRS
Stars: ✭ 15 (-86.96%)
Mutual labels:  hibernate, jpa, jwt
Kotlin Spring Boot Jpa Rest Api Demo
Build a Restful API with Kotlin, Spring Boot, Mysql, Jpa and Hibernate
Stars: ✭ 67 (-41.74%)
Mutual labels:  hibernate, jpa, mysql
Angularjs Springmvc Sample Boot
A RESTful sample using Spring Boot, Spring MVC, Spring Data and Angular/Bootstrap.
Stars: ✭ 309 (+168.7%)
Mutual labels:  hibernate, jpa, spring
Atom
Java course materials
Stars: ✭ 293 (+154.78%)
Mutual labels:  hibernate, jpa, spring
Hibernate Springboot
Collection of best practices for Java persistence performance in Spring Boot applications
Stars: ✭ 589 (+412.17%)
Mutual labels:  hibernate, jpa, mysql
Curso Sistemas Web Com Spring Javascript Bootstrap
Stars: ✭ 74 (-35.65%)
Mutual labels:  hibernate, jpa, spring
Spring Boot Demo
Spring Boot & Spring Cloud & Spring Security Demo Case(Spring学习示例实战项目)
Stars: ✭ 255 (+121.74%)
Mutual labels:  jpa, mysql, spring
Jsf2.2 Spring4 Hibernate4 Mysql
Full configured JSF2.2.10, Primefaces5, Spring4, Hibernate4/MySQL working project
Stars: ✭ 10 (-91.3%)
Mutual labels:  hibernate, mysql, spring
Ebean
Ebean ORM
Stars: ✭ 1,172 (+919.13%)
Mutual labels:  jpa, database, mysql

Spring Boot 2 OAuth2 JWT Authorization Server

Link to Spring Boot 2 OAuth2 JWT Resource Server project


Simple project on how to setup OAuth2 authorization server with JWT tokens using Spring Boot 2, JPA, Hibernate and MySQL.

In Short

All Users and Clients are stored in the database. Users can have many Roles associated with them and Roles can have many Permissions associated with them which in the end are added as a list of authorities in the JWT token.

First we must generate a KeyStore file. To do that execute the following command:

keytool -genkeypair -alias jwt -keyalg RSA -keypass password -keystore jwt.jks -storepass password

(if you're under Windows go your Java install dir and there you'll find a jar named keytool)

The command will generate a file called jwt.jks which contains the Public and Private keys.

It is recommended to migrate to PKCS12. To do that execute the following command:

keytool -importkeystore -srckeystore jwt.jks -destkeystore jwt.jks -deststoretype pkcs12

Now let's export the public key:

keytool -list -rfc --keystore jwt.jks | openssl x509 -inform pem -pubkey

Copy the jwt.jks file to the Resources folder.

Copy from (including) -----BEGIN PUBLIC KEY----- to (including) -----END PUBLIC KEY----- and save it in a file. You'll need this later in your resource servers.

There's a custom User class which implements the UserDetails interface and has all the required methods and an additional email field;

There's the UserRepository in which there are 2 methods, one for finding a User entity by username and the other by email. This means we can authenticate a User based on the username or the email.

In order to use our custom User object we must provide with a CustomUserDetailsService which implements the UserDetailsService. The loadUserByUsername method is overriden and set up to work with our logic.

Database oauth2.sql and application.yml

The database with all the tables and a test client and users. Check the configuration in the application.yml file.

Users

username: admin or user

password: password

Clients

client: adminapp

secret: password

The admin is associated with a role_admin and that role is associated with several permissions. The user is associated with a role_user and read permissions.

checkUserScopes

If checkUserScopes is set to false (default Spring Boot 2 functionality), no checks will be done between the client scope and the user authorities.

If checkUserScopes is set to true (see documentation below), then when a user tries to authenticate with a client, we check whether at least one of the user authorities is contained in the client scope. (I don't know why the default implementation is not done like this)

checkUserScopes is set as a property inside the application.yml file.

check-user-scopes: true

And we get the value in the OAuth2Configuration class.

@Value("${check-user-scopes}")
private Boolean checkUserScopes;

Configure WebSecurity

In Spring Boot 2 you must use the DelegatingPasswordEncoder.

@Bean
public PasswordEncoder passwordEncoder() {
	return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}

AuthenticationManagerBean

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
	return super.authenticationManagerBean();
}

Configure AuthenticationManagerBuilder

@Autowired
private UserDetailsService userDetailsService;

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
	auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

HTTP Security configuration

@Override
public void configure(HttpSecurity http) throws Exception {
	http.csrf().disable().exceptionHandling()
			.authenticationEntryPoint(
					(request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
			.and().authorizeRequests().antMatchers("/**").authenticated().and().httpBasic();
}

Configure OAuth2

@Configuration
@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {...

There must be an AuthenticationManager provided

@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;

Autowire the DataSource and set OAuth2 clients to use the database and the PasswordEncoder.

@Autowired
private DataSource dataSource;

@Autowired
private PasswordEncoder passwordEncoder;

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
	clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
}

Configure the endpoints to use the custom beans.

@Autowired
private UserDetailsService userDetailsService;

@Bean
public TokenStore tokenStore() {
	return new JwtTokenStore(jwtAccessTokenConverter());
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		endpoints.tokenStore(tokenStore()).tokenEnhancer(jwtAccessTokenConverter())
			.authenticationManager(authenticationManager).userDetailsService(userDetailsService);
}

Configure who has acces to the OAuth2 server

@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
	oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}

In order to add additional data in the JWT token we must implement a CustomTokenEnchancer.

protected static class CustomTokenEnhancer extends JwtAccessTokenConverter {
	@Override
	public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
		User user = (User) authentication.getPrincipal();

		Map<String, Object> info = new LinkedHashMap<String, Object>(accessToken.getAdditionalInformation());

		info.put("email", user.getEmail());

		DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
		customAccessToken.setAdditionalInformation(info);

		return super.enhance(customAccessToken, authentication);
	}
}

Configure the token converter.

@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
	JwtAccessTokenConverter converter = new CustomTokenEnhancer();
	converter.setKeyPair(
			new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "password".toCharArray()).getKeyPair("jwt"));
	return converter;
}

In order to make checkUserScopes to work, you must set that field in the RequestFactory and configure Spring to use that factory in the endpoints configuration. This should've worked just like this but for some reason when the checkUserScopes is enabled the authentication of a user works fine but the refresh token is not working. When you hit the token endpoint with the refresh token, Spring sets the Authentication in the Security Context to be the one of the client, not the user from the refresh token and it doesn't update it later. This means when checks are done on the scope and authorities you always get the authorities from the client, not the user.

I've created a CustomOAuth2RequestFactory that extends the DefaultOAuth2RequestFactory and override the createTokenRequest method where I get the Authentication from the refresh token, autowire the userDetailsService, get the User from the database and manually update the Security Context. This means if there are any changes to the User we always check for details from the database and not the refresh token itself.

class CustomOauth2RequestFactory extends DefaultOAuth2RequestFactory {
	@Autowired
	private TokenStore tokenStore;

	public CustomOauth2RequestFactory(ClientDetailsService clientDetailsService) {
		super(clientDetailsService);
	}

	@Override
	public TokenRequest createTokenRequest(Map<String, String> requestParameters,
			ClientDetails authenticatedClient) {
		if (requestParameters.get("grant_type").equals("refresh_token")) {
			OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(
					tokenStore.readRefreshToken(requestParameters.get("refresh_token")));
			SecurityContextHolder.getContext()
					.setAuthentication(new UsernamePasswordAuthenticationToken(authentication.getName(), null,
							userDetailsService.loadUserByUsername(authentication.getName()).getAuthorities()));
		}
		return super.createTokenRequest(requestParameters, authenticatedClient);
	}
}

Define a requestFactory bean. You'll also need the clientDetailsService here.

@Autowired
private ClientDetailsService clientDetailsService;

@Bean
public OAuth2RequestFactory requestFactory() {
	CustomOauth2RequestFactory requestFactory = new CustomOauth2RequestFactory(clientDetailsService);
	requestFactory.setCheckUserScopes(true);
	return requestFactory;
}

Last step is to configure the endpoints to use this requestFactory. Because we are doing check on the checkUserScopes we have this in the endpoints configuration method.

if (checkUserScopes)
	endpoints.requestFactory(requestFactory());

Installing

Just clone or download the repo and import it as an existing maven project.

You'll also need to set up Project Lombok or if you don't want to use this library you can remove the associated annotations from the code and write the getters, setters, constructors, etc. by yourself.

Use

To test it I used HTTPie. It's similar to CURL.

To get a JWT token execute the following command:

http --form POST adminapp:[email protected]:9999/oauth/token grant_type=password username=admin password=password
ACCESS_TOKEN={the access token}
REFRESH_TOKEN={the refresh token}

To access a resource use (you'll need a different application which has configured ResourceServer):

http localhost:8080/users 'Authorization: Bearer '$ACCESS_TOKEN

To use the refresh token functionality:

http --form POST adminapp:[email protected]:9999/oauth/token grant_type=refresh_token refresh_token=$REFRESH_TOKEN

License

This project is licensed under the MIT License - see the LICENSE file for details.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].