Skip to content

SChoi005/spring-security-example

Repository files navigation

Spring-Security

Http Protocol Characteristic

  1. Connectionless
    • When a client and server exchange a request and a response once, disconnect.
  2. Stateless
    • After communication, not stay state information
  • So, due to these characteristics, can stay information of user authentication, using Session&Cookie or jwt.

Login ways

  • Session&Cookie
  • JWT(Json Web Token) token
  • OAuth(Open Authentication)

Basic Terms

  • Principal : Target to access to protected resource.
  • Authentication : Process to check who access protected resource and subject being able to conduct tasks. => who?
  • Authorization : After authentication, process to check which resources principal can access. => what authorities does principal have?
  • Credential : Principal's password accessing resource.

Spring-Security feature and structure

  • Conducting based on Filter apart from MVC.
  • Basically, authentication through session and cookie
  • Managing resource access through Authentication Manager(Authentication) and Access Decision Manager(Authorization).
  • Authentication Manager is conducted by UsernamePasswordAuthenticationFilter.
  • Access Decision Manager is conducted by FilterSecurityInterceptor.

Start Spring-Security

Working principle

  • Authentication -> After Authentication succeeds -> Authorization
  • Authentication information basically stores at in-memory session storage(SecurityContextHolder) as session-cookie way.
  1. Basically, if request about authentication based on ID, PASSWORD comes about, it reaches UsernamePasswordAuthenticationFilter of Authentication Filters.
  2. * If not ID, PASSWORD, but OAuth2.0 or JWT is used, other filter is used. (ex : OAuth2ClientAuthenticationProcessingFilter)
  3. If the request reaches UsernamePasswordAuthenticationFilter, attemptAuthentication(request,response) method works. This method creates UsernamePasswordAuthenticationToken(Authentication) by bringing username and password from the request.
  4. AuthenticationManager(ProviderManager) authorize by using UsernamePasswordAuthentciationToken(Authentication)

Code

  1. Add dependency

        compile('org.springframework.boot:spring-boot-starter-security')
    
  2. Java Configuration

        @EnableWebSecurity // Automatically, contain SpringSecurityFilterChain
        public class SecurityConfig extends WebSecurityConfigurerAdapter{
            ...   
            
            @Override
            protected void configure(HttpSecurity http) throws Exception {
    
                String[] permmited = {
                                      "/api/user/signUp","/"
                                     };
                // Setting cors, csrf 
                http.cors().and().csrf().disable();
    
                // Setting permission of end point and authorize
                http.authorizeRequests()
                        .antMatchers(permmited).permitAll()
                        .antMatchers("/professor").hasRole("PROFESSOR")
                        .antMatchers("/student").hasAnyRole("STUDENT","PROFESSOR")
                    .and()
                        .formLogin()
                        .loginPage("/")
                        .defaultSuccessUrl("/student")
                        .usernameParameter("userID") // Coincide loginform name
                    .and()
                        .logout()
                        .logoutSuccessUrl("/")
                        .invalidateHttpSession(true)
                        .deleteCookies("JSESSIONID")
                    .and()
                        .exceptionHandling()
                        .accessDeniedPage("/accessDenied");
    
                // Session management
                http.sessionManagement()
                        .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
                        .sessionFixation()
                        .changeSessionId()
                        .maximumSessions(1) 
                        .maxSessionsPreventsLogin(false)
                        .expiredUrl("/")
                        .sessionRegistry(sessionRegistry())
                    .and()
                        .invalidSessionUrl("/");
                        
            }
    
            @Bean
            public SessionRegistry sessionRegistry() {
                return new SessionRegistryImpl();
            }
        }
    • sessionCreationPolicy(SessionCreationPolicy.ALWAYS) => Setting session creation policy
      • SessionCreationPolicy.ALWAYS  => Always create session
      • SessionCreationPolicy.IF_REQUIRED => (Basic)Create when be required
      • SessionCreationPolicy.NEVER => Not create, but if session is existed, use it
      • SessionCreationPolicy.STATELESS => Not create, use existed session(JWT)
    • sessionFixation() => Setting about session-fixation attack
      • changeSessionId() => Issue new sessionId, and capable of using prior session
      • newSession() => Issue new sessionId, and not capable of using prior session
      • none() => Nothing
    • maximumSessions(1) => Restrict maximum session
    • maxSessionsPreventsLogin(false)
      • True => Later user's session is blocked
        • If don't normally logout and close browser, occur anyone doesn't login
      • False => Prior user's session is expired
    • expiredUrl("/") => Url when dupliciate login
    • sessionRegistry(sessionRegistry())
      • If not add sessionRegistry(sessionRegistry()), when user login again after logout, occur error "Maximum sessions of 1 for this principal exceeded".
    • invalidSessionUrl("/") => Url when session is expired
  3. Implementation UserDetails

        
        public class User implements UserDetails {
    
            @Id
            @GeneratedValue(strategy = GenerationType.IDENTITY)
            private Long id;
    
            private String username;
    
            private String password;
    
            @Column(name = "role")
            @Enumerated(EnumType.STRING)
            private Role role;
    
            @Override
            public String getPassword() {
                return password;
            }
    
            @Override
            public String getUsername() {
                return username;
            }
    
            // Return Authority lists user has
            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                ArrayList<GrantedAuthority> auth = new ArrayList<>();
                auth.add(new SimpleGrantedAuthority(role.toString()));
                return auth;
            }
    
            @Override
            public boolean isEnabled() {
                return true;
            }
    
            @Override
            public boolean isCredentialsNonExpired() {
                return true;
            }
    
            @Override
            public boolean isAccountNonExpired() {
                return true;
            }
    
            @Override
            public boolean isAccountNonLocked() {
                return true;
            }
        }
  4. Implementation UserDetailsService

        
        @Service
        public class UserService implements UserDetailsService{
    
            ...
    
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                User user = userRepository.findByUsername(username);
                if(user != null)
                    return user;
                else
                    throw new UsernameNotFoundException(username);
            }
    
        }