Spring Boot Oauth2 login and signup Implementation using In-memory Database
Purpose: In this post, we will learn how we can implement Oauth2. The steps are given below.
1. Setup and Create Project: Visit here. Spring Boot Rest API Hello World Examples.
Next Step. Spring Boot Parent Dependencies.
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.6.RELEASE</version><relativePath /> <!-- lookup parent from repository --></parent>
Next Step. INmemory Database Dependencies.
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope></dependency>
Next Step. Oauth2 dependency Dependencies.
<dependency><groupId>org.springframework.security.oauth</groupId><artifactId>spring-security-oauth2</artifactId><version>2.3.6.RELEASE</version></dependency>
Next Step. Spring Boot main class.
Class: Application.java
Note: @SpringBootApplication=@Configuration+ @EnableAutoConfiguration+ @ComponentScan.
package com.bce;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
Next Step. Add below line in application.properties for In-memory DB and Oauth2 configuration and change yellow highted line if port changed.
server.port=8080server.servlet.context-path=/apispring.jackson.default-property-inclusion=NON_NULLspring.datasource.driverClassName=org.h2.Driverspring.datasource.username=saspring.datasource.password=spring.jpa.database-platform=org.hibernate.dialect.H2Dialect#enabling the H2 consolespring.h2.console.enabled=truespring.jpa.show-sql=truespring.jpa.generate-ddl=truespring.jpa.hibernate.ddl-auto=updatespring.datasource.url=jdbc:h2:C:/data/oauth2# Custom H2 Console URLspring.h2.console.path=/h2#Application specificauthentication.oauth.clientid=springbootrestauthentication.oauth.secret=restserviceauthentication.oauth.tokenValidityInSeconds=6000#2592000authentication.oauth.refreshTokenValidityInSeconds=10000authentication.oauth.grant.type=passwordauthentication.oauth.grant.refresh.type=refresh_token#2592000authentication.oauth.token.url=http://localhost:8080/apiauth.server.schem=httplogging.level.org.springframework.boot.autoconfigure=ERROR#spring.main.allow-circular-references: true
Next Step. OAuth Configuration add below java file (OAuthConfiguration.java)
package com.bce.configuration;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.factory.PasswordEncoderFactories;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;import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;import org.springframework.security.oauth2.provider.token.TokenStore;import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;@Configuration@EnableAuthorizationServerpublic class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {@Value("${authentication.oauth.clientid:clientid}")private String PROP_CLIENTID;@Value("${authentication.oauth.secret:secret}")private String PROP_SECRET;@Value("${authentication.oauth.tokenValidityInSeconds:60}")private Integer PROP_TOKEN_VALIDITY_SECONDS;@Value("${authentication.oauth.refreshTokenValidityInSeconds:120}")private Integer PROP_REFRESH_TOKEN_VALIDITY_SECONDS;@Autowired@Qualifier("authenticationManagerBean")private AuthenticationManager authenticationManager;@AutowiredUserDetailsService userDetailsService;@Overridepublic void configure(final AuthorizationServerSecurityConfigurer oauthServer) throws Exception {oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");}@Beanpublic PasswordEncoder passwordEncoder() {return PasswordEncoderFactories.createDelegatingPasswordEncoder();}@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {clients.inMemory().withClient(PROP_CLIENTID).secret(passwordEncoder().encode(PROP_SECRET)).authorizedGrantTypes("password", "authorization_code", "refresh_token").scopes("read","write").authorities("USER","ADMIN").autoApprove(true).accessTokenValiditySeconds(PROP_TOKEN_VALIDITY_SECONDS).refreshTokenValiditySeconds(PROP_REFRESH_TOKEN_VALIDITY_SECONDS);}@Overridepublic void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).accessTokenConverter(defaultAccessTokenConverter()).userDetailsService(userDetailsService);}@Beanpublic TokenStore tokenStore(){return new JwtTokenStore(defaultAccessTokenConverter());}@Beanpublic JwtAccessTokenConverter defaultAccessTokenConverter() {JwtAccessTokenConverter converter = new JwtAccessTokenConverter();converter.setSigningKey("123");return converter;}}
Next Step. OAuth Configuration add below java file (SecurityConfig.java)
package com.bce.configuration;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.authentication.dao.DaoAuthenticationProvider;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.WebSecurity;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;import com.bce.service.UserDetailsServiceImpl;@EnableWebSecurity@EnableGlobalMethodSecurity(securedEnabled = true)public class SecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredUserDetailsServiceImpl userDetailsService;@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/pages/");}@Beanpublic DaoAuthenticationProvider authenticationProvider() {DaoAuthenticationProvider provider = new DaoAuthenticationProvider();provider.setPasswordEncoder(bCryptPasswordEncoder());provider.setUserDetailsService(userDetailsService);return provider;}@Beanpublic BCryptPasswordEncoder bCryptPasswordEncoder() {return new BCryptPasswordEncoder();}@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {auth.authenticationProvider(authenticationProvider());}}
Next Step: add ResourceServerConfiguration.java file.
package com.bce.configuration;import org.springframework.context.annotation.Configuration;import org.springframework.security.config.annotation.web.builders.HttpSecurity;import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;@Configuration@EnableResourceServerpublic class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {private static final String RESOURCE_ID = "oauth2-api";@Overridepublic void configure(ResourceServerSecurityConfigurer resources) {resources.resourceId(RESOURCE_ID);}@Overridepublic void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/", "/user", "/oauth/token").permitAll();http.csrf().disable();http.antMatcher("/**").authorizeRequests().anyRequest().authenticated();}}
Next Step: Signup process.
Open URL as given in below image and signup:
Given below method will be call after singup call.
A. Add signup method in LoginController.java
@RequestMapping(value = "/signup", method = RequestMethod.POST)public ResponseEntity<CustomResponse<Login>> signup(@RequestBody LoginBO login) {log.info("user enter in signup()..");Login loginDB = loginService.signup(login);if (loginDB != null && loginDB.getLoginStatus() != StatusCode.ALREADY_EXIST) {ResponseEntity<Object> result = loginService.generateAuthToken(login.getEmailId(), login.getPassword());if (result != null && result.getStatusCode() == HttpStatus.OK) {CustomResponse<Login> customResponse = new CustomResponse<Login>(loginDB);loginDB.setPassword(null);customResponse.setData(loginDB);customResponse.setMessage("User created successfully");customResponse.setStatus("CREATED");customResponse.setToken(result.getBody());return new ResponseEntity<>(customResponse, HttpStatus.CREATED);} else {CustomResponse<Login> customResponse = new CustomResponse<Login>(loginDB);customResponse.setMessage("Authentication failed");customResponse.setStatus("UNAUTHORIZED");return new ResponseEntity<>(customResponse, HttpStatus.UNAUTHORIZED);}} else {CustomResponse<Login> customResponse = new CustomResponse<Login>(loginDB);customResponse.setMessage("Provided details al-ready exist");customResponse.setStatus("ALREADY");customResponse.setData(null);return new ResponseEntity<>(customResponse, HttpStatus.CONFLICT);}}
B. In LoginServiceImpl.java added signup method implementation. In given below method we are checking existing using is present in DB.
@Overridepublic Login signup(LoginBO signupLogin) {Login login = checkExistingUserByEmail(signupLogin);if (login != null) {login.setLoginStatus(StatusCode.ALREADY_EXIST);return login;}{login = new Login();login.setPassword(new BCryptPasswordEncoder().encode(signupLogin.getPassword()));login.setLoginStatus(StatusCode.VERIFICATION_PENDING);if (signupLogin.getEmailId() != null) {login.setVerifyEmail(StatusCode.VERIFICATION_PENDING);login.setEmailId(signupLogin.getEmailId());}if (signupLogin.getMobile() != null) {login.setVerifyMobile(StatusCode.VERIFICATION_PENDING);login.setMobile(signupLogin.getMobile());}login.setLoginTypeEnum(signupLogin.getLoginTypeEnum());login.setCreatedTime(new Date());Login lDB = this.loginRepository.save(login);return lDB;}}
Below are the signup response:
Next Step: After Signup. Below are given login process.
A. Add login method in LoginController.java. In given below method first we are checking the using in DB with username and password. If your is valid the we call generate token method.
@RequestMapping(value = "/loginuser", method = RequestMethod.POST)public ResponseEntity<CustomResponse<Login>> login(@RequestBody LoginBO login) {log.info("user enter in login()..");Login loginDB = loginService.login(login);if (loginDB != null) {ResponseEntity<Object> result = loginService.generateAuthToken(login.getEmailId(), login.getPassword());if (result != null && result.getStatusCode() == HttpStatus.OK) {CustomResponse<Login> customResponse = new CustomResponse<Login>(loginDB);customResponse.setMessage("Login Successfully");customResponse.setStatus("SUCCESS");customResponse.setToken(result.getBody());loginDB.setPassword(null);customResponse.setData(loginDB);return new ResponseEntity<>(customResponse, HttpStatus.OK);} else {CustomResponse<Login> customResponse = new CustomResponse<Login>(loginDB);customResponse.setMessage("Authentication failed");customResponse.setStatus("UNAUTHORIZED");customResponse.setData(null);return new ResponseEntity<>(customResponse, HttpStatus.UNAUTHORIZED);}} else {CustomResponse<Login> customResponse = new CustomResponse<Login>(loginDB);customResponse.setMessage("Detail does not match");customResponse.setStatus("FAIL");return new ResponseEntity<>(customResponse, HttpStatus.NOT_FOUND);}}
B. In LoginServiceImpl.java added login method implementation. In given below method we are checking is user valid in DB.
@Overridepublic Login login(LoginBO login) {Login loginDB = this.loginRepository.findByEmailId(login.getEmailId());if (loginDB != null && checkPassword(loginDB.getPassword(), login.getPassword())) {return loginDB;} else {return null;}}
C: Below are the method is using for generate authentication token to call API.
@Overridepublic ResponseEntity<Object> generateAuthToken(String username, String password) {try {String authentication = PROP_CLIENTID + ":" + PROP_SECRET;HttpHeaders headers = new HttpHeaders();headers.add("Authorization", "Basic " + Base64.getEncoder().encodeToString(authentication.getBytes()));headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));RestTemplate restTemplate = new RestTemplate();HttpEntity<String> requestEnty = new HttpEntity<>(headers);String URL = OAUTH_TOKEN_URL + "/oauth/token";URL += "?username=" + username;URL += "&grant_type=" + OAUTH_GRANT_TYPE;URL += "&password=" + password;ResponseEntity<Object> result = restTemplate.exchange(URL, HttpMethod.POST, requestEnty, Object.class);return result;} catch (RestClientException e) {e.printStackTrace();return null;}}
Download Code from GitHub. Download
No comments:
Post a Comment