Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reddit-dev-002-fix-securityConfig - refactor securityConfig, update main app annotation #73

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableAsync;

//@SpringBootApplication
@SpringBootApplication
// disable spring security for now
@SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
//@SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
//@EnableAsync // https://youtu.be/PMr2Mh9xzm4?t=305
//@ComponentScan(basePackages="com.yen.SpringReddit.mapper")
@ComponentScan(basePackages={
"com.yen.SpringReddit.security.JwtProvider"})
//@Import(OpenAPIConfiguration.class)
public class SpringRedditApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,72 +4,155 @@
// https://youtu.be/1ojKQxVssPQ?t=187
// https://github.com/SaiUpadhyayula/spring-reddit-clone/blob/master/src/main/java/com/programming/techie/springredditclone/config/SecurityConfig.java

import org.springframework.beans.factory.annotation.Autowired;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler;
import org.springframework.security.web.SecurityFilterChain;

// TODO : double check if should use WebSecurityConfigurerAdapter or not
public class SecurityConfig extends SecurityConfigurerAdapter {
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

@Autowired
UserDetailsService userDetailsService;
@Configuration
@RequiredArgsConstructor
public class SecurityConfig {

@Autowired
PasswordEncoder passwordEncoder;
@Value("${jwt.public.key}")
RSAPublicKey publicKey;

@Bean(BeanIds.AUTHENTICATION_MANAGER)
@Value("${jwt.private.key}")
RSAPrivateKey privateKey;

@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
return httpSecurity
//.cors().and()
.csrf().disable()
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/api/auth/**")
.permitAll()
// .requestMatchers(HttpMethod.GET, "/api/subreddit")
// .permitAll()
// .requestMatchers(HttpMethod.GET, "/api/posts/")
// .permitAll()
// .requestMatchers(HttpMethod.GET, "/api/posts/**")
// .permitAll()
// .requestMatchers("/v2/api-docs",
// "/configuration/ui",
// "/swagger-resources/**",
// "/configuration/security",
// "/swagger-ui.html",
// "/webjars/**")
// .permitAll()
// .anyRequest()
// .authenticated()
)
// .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
// .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
// .exceptionHandling(exceptions -> exceptions
// .authenticationEntryPoint(new BearerTokenAuthenticationEntryPoint())
// .accessDeniedHandler(new BearerTokenAccessDeniedHandler())
// )
.build();
}

// @Bean
// public AuthenticationManager authenticationManagerBean() throws Exception {
// return super.authenticationManagerBean();
// PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }

//
// @Bean
// public UserDetailsService myUserDetailsService(){
// return new InMemoryUserDetailsManager(
// User.withUsername("admin")
// .password("{noop}123")
// .authorities("READ", "ROLE_USER")
// .build());
// JwtDecoder jwtDecoder() {
// return NimbusJwtDecoder.withPublicKey(this.publicKey).build();
// }

public void configure(HttpSecurity httpSecurity) throws Exception {

httpSecurity
.csrf()
.disable()
.authorizeRequests()
//.requestMatchers("/api/auth/**")
//.permitAll()
.anyRequest()
.authenticated();
}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}

// encrypt user password (for saving it in DB)
// https://youtu.be/kpKUMmAmcj0?t=297
//
// @Bean
// PasswordEncoder passwordEncoder(){
// return new BCryptPasswordEncoder();
// JwtEncoder jwtEncoder() {
// JWK jwk = new RSAKey.Builder(this.publicKey).privateKey(this.privateKey).build();
// JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
// return new NimbusJwtEncoder(jwks);
// }

}


//// TODO : double check if should use WebSecurityConfigurerAdapter or not
//public class SecurityConfig extends SecurityConfigurerAdapter {
//
// @Autowired
// UserDetailsService userDetailsService;
//
// @Autowired
// PasswordEncoder passwordEncoder;
//
// @Bean(BeanIds.AUTHENTICATION_MANAGER)
// public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
// return authenticationConfiguration.getAuthenticationManager();
// }
//
//// @Bean
//// public AuthenticationManager authenticationManagerBean() throws Exception {
//// return super.authenticationManagerBean();
//// }
//
//// @Bean
//// public UserDetailsService myUserDetailsService(){
//// return new InMemoryUserDetailsManager(
//// User.withUsername("admin")
//// .password("{noop}123")
//// .authorities("READ", "ROLE_USER")
//// .build());
//// }
//
// public void configure(HttpSecurity httpSecurity) throws Exception {
//
// httpSecurity
// .csrf()
// .disable()
// .authorizeRequests()
// //.requestMatchers("/api/auth/**")
// //.permitAll()
// .anyRequest()
// .authenticated();
// }
//
// @Autowired
// public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
// authenticationManagerBuilder
// .userDetailsService(userDetailsService)
// .passwordEncoder(passwordEncoder);
// }
//
// // encrypt user password (for saving it in DB)
// // https://youtu.be/kpKUMmAmcj0?t=297
//// @Bean
//// PasswordEncoder passwordEncoder(){
//// return new BCryptPasswordEncoder();
//// }
//
//}
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
//package com.yen.SpringReddit.controller;
//
//// https://youtu.be/kpKUMmAmcj0?t=123
//
//import com.yen.SpringReddit.dto.LoginRequest;
//import com.yen.SpringReddit.dto.RegisterRequest;
//import com.yen.SpringReddit.po.User;
//import com.yen.SpringReddit.service.AuthService;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.http.HttpStatus;
//import org.springframework.http.ResponseEntity;
//import org.springframework.security.authentication.AuthenticationManager;
//import org.springframework.web.bind.annotation.*;
//
//
//@RestController
//@RequestMapping("/api/auth")
//public class AuthController {
//
// @Autowired
// AuthService authService;
//
// @PostMapping("/signup")
// public ResponseEntity signup(@RequestBody RegisterRequest registerRequest){
//
// authService.signUp(registerRequest);
// return new ResponseEntity<>("User register success", HttpStatus.OK);
// }
//
// @GetMapping("accountVerification/{token}")
// public ResponseEntity<String> verifyAccount(@PathVariable String token){
//
// authService.verifyAccount(token);
// return new ResponseEntity<>("Account activation success", HttpStatus.OK);
// }
//
// @PostMapping("/login")
// public void login(@RequestBody LoginRequest loginRequest){
//
// authService.login(loginRequest);
// }
//
//}
package com.yen.SpringReddit.controller;

// https://youtu.be/kpKUMmAmcj0?t=123

import com.yen.SpringReddit.dto.LoginRequest;
import com.yen.SpringReddit.dto.RegisterRequest;
import com.yen.SpringReddit.service.AuthService;
import com.yen.SpringReddit.service.impl.AuthServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/api/auth")
public class AuthController {

@Autowired
AuthService authService;

@PostMapping("/signup")
public ResponseEntity signup(@RequestBody RegisterRequest registerRequest){

authService.signup(registerRequest);
return new ResponseEntity<>("User register success", HttpStatus.OK);
}

@GetMapping("accountVerification/{token}")
public ResponseEntity<String> verifyAccount(@PathVariable String token){

authService.verifyAccount(token);
return new ResponseEntity<>("Account activation success", HttpStatus.OK);
}

@PostMapping("/login")
public void login(@RequestBody LoginRequest loginRequest){

authService.login(loginRequest);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,50 @@
//package com.yen.SpringReddit.security;
package com.yen.SpringReddit.security;
//
//// https://youtu.be/1ojKQxVssPQ?t=610


import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.jwt.JwtClaimsSet;
import org.springframework.security.oauth2.jwt.JwtEncoder;
import org.springframework.security.oauth2.jwt.JwtEncoderParameters;
import org.springframework.stereotype.Service;

import java.time.Instant;

@Service
@RequiredArgsConstructor
public class JwtProvider {

private final JwtEncoder jwtEncoder;
@Value("${jwt.expiration.time}")
private Long jwtExpirationInMillis;

public String generateToken(Authentication authentication) {
User principal = (User) authentication.getPrincipal();
return generateTokenWithUserName(principal.getUsername());
}

public String generateTokenWithUserName(String username) {
JwtClaimsSet claims = JwtClaimsSet.builder()
.issuer("self")
.issuedAt(Instant.now())
.expiresAt(Instant.now().plusMillis(jwtExpirationInMillis))
.subject(username)
.claim("scope", "ROLE_USER")
.build();

return this.jwtEncoder.encode(JwtEncoderParameters.from(claims)).getTokenValue();
}

public Long getJwtExpirationInMillis() {
return jwtExpirationInMillis;
}
}


//
//// V1
//// https://github.com/SaiUpadhyayula/spring-reddit-clone/blob/master/src/main/java/com/programming/techie/springredditclone/security/JwtProvider.java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

public interface AuthService {

void signUp(RegisterRequest registerRequest);
void signup(RegisterRequest registerRequest);

String generateVerificationToken(User user);

Expand Down
Loading