Spring Security is used in SpringBoot 2.x front-end and back-end separation projects to customize validation

demo git address: Portal

First: Preface

	Now most of them are front-end and back-end projects. In hard coding, jumping to a page path is obviously inappropriate, so the server should return to JSON.
To inform the front-end whether to log in, whether to have page permissions, whether to log in overtime, etc., according to the return of JSON agreed value, the front-end from the free jump.

Second: concrete realization

1. Setting up state configuration classes such as successful login, failure, no privilege, etc.

Access Denied Handler Config

@Component
public class AccessDeniedHandlerConfig implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
        JSONObject result = new JSONObject();
        result.put("msg","No permission!");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.getWriter().println(result.toJSONString());
    }
}

Authentication Entry Point Config (not logged in)

@Component
public class AuthenticationEntryPointConfig implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        JSONObject json = new JSONObject();
        json.put("msg","Not logged in");
        httpServletResponse.setContentType("application/json;charset=utf-8");

        httpServletResponse.getWriter().write("null");
    }
}

Authentication Failure Handler Config

@Component
public class AuthenticationFailureHandlerConfig implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        JSONObject json = new JSONObject();
        json.put("msg","Logon failure");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.getWriter().write(json.toJSONString());
    }
}

Authentication Success Handler Config

@Component
public class AuthenticationSuccessHandlerConfig implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        JSONObject json = new JSONObject();
        json.put("msg","Successful login");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.getWriter().write(json.toJSONString());
    }
}

Logout Handler Config

@Component
public class LogoutHandlerConfig implements LogoutHandler {

    @Override
    public void logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) {
        try {
            String url = httpServletRequest.getParameter("redirectUrl");
            //Implementing custom redirection
            httpServletResponse.sendRedirect(url);
        }catch (IOException e){

        }
    }
}

Logout path: localhost:8080/logout
redirectUrl is a custom jump url address for the front end, otherwise it will automatically jump to the default security address after logout, such as:

Logout Success Handler Config (Logout Successful Configuration)

@Component
public class LogoutSuccessHandlerConfig implements LogoutSuccessHandler {

    @Override
    public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        JSONObject result = new JSONObject();
        result.put("msg","Cancellation!");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        httpServletResponse.getWriter().write(result.toJSONString());
    }
}

2. model preparation

SysUser,SysRole,SysUserRole

@Data
public class SysUser implements Serializable {

    private String userId;

    private String userName;

    private String password;

    private String updateUserId;

    private String createUserId;

    private LocalDateTime updateTime;

    private LocalDateTime createTime;

}
@Data
public class SysRole implements Serializable {

    private String roleId;

    private String name;

    private Integer state;

    private String updateUserId;

    private String createUserId;

    private LocalDateTime updateTime;

    private LocalDateTime createTime;

}
@Data
public class SysUserRole implements Serializable {

    private String userRoleId;

    private String roleId;

    private String userId;

    private String updateUserId;

    private String createUserId;

    private LocalDateTime updateTime;

    private LocalDateTime createTime;

}

Principle of Custom Verification Mechanism

User Name Password - > (Authentication (Unauthenticated) - >
AuthenticationManager  -> AuthenticationProvider ->
UserDetailService - > UserDetails - > Authentication (certified) passed

3. Define User Object, Implement User Details Service, SelfAuthentication Provider Class

Create SelfUserDetails

@Data
public class SelfUserDetails implements UserDetails, Serializable {
    private String username;
    private String password;
    private Set<? extends GrantedAuthority> authorities;


    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

Create SelfUser Details Service to implement User Details Service

@Service
public class SelfUserDetailsService implements UserDetailsService {

    @Autowired
    SysUserService sysUserService;


    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        SelfUserDetails userInfo = new SelfUserDetails();
        userInfo.setUsername(userName);
        SysUser sysUser = sysUserService.getUserByUsername(userName);
        if (sysUser == null) {
            throw new UsernameNotFoundException("Users do not exist!");
        }
        userInfo.setPassword(sysUser.getPassword());
        SysRole sysRole = sysUserService.getUserRoleInfo(sysUser.getUserId());
        if (sysRole == null) {
            throw new UsernameNotFoundException("Users are not allotted permissions!");
        }
        if (sysRole.getState() == 0) {
            throw new UsernameNotFoundException("User privileges are invalid!");
        }
        userInfo.setAuthorities(getAuthorities(sysRole.getName()));
        return userInfo;
    }
    private Set<GrantedAuthority> getAuthorities(String role) {
        Set<GrantedAuthority> authoritiesSet = new HashSet();
        GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role);
        authoritiesSet.add(grantedAuthority);
        return authoritiesSet;
    }

}

Create the SelfAuthentication Provider class to implement Authentication Provider

public class SelfAuthenticationProvider implements AuthenticationProvider {


    @Autowired
    SelfUserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String userName = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();


        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encodePwd = bCryptPasswordEncoder.encode(password);

        UserDetails userInfo = userDetailsService.loadUserByUsername(userName);
        if (userInfo == null) {
            throw new UsernameNotFoundException("user does not exist");
        }
        if(!userInfo.getPassword().equals(encodePwd)) {
            throw new BadCredentialsException("Password error");
        }

        return new UsernamePasswordAuthenticationToken(userName, password, userInfo.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.equals(authentication);
    }
}

4. Privilege Configuration Class

Create RbacService (role-Based-access control) permission control, url permission part is not implemented, interested partners can work together to improve.

@Service("rbacService")
public class RbacServiceImpl implements RbacService {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    
    @Override
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        String userName = (String) authentication.getPrincipal();
        //Read whether the current user has url privileges
        //todo not implemented
        if (antPathMatcher.match("", request.getRequestURI())) {
            return true;
        }
        return false;
    }
}

5. Configuring security

Create the Security Config configuration class, configure the core:

 @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint)
                .and()
                .authorizeRequests()
                .antMatchers("/role/**").hasRole("admin")
                // This means that / index is a page that does not require authorization and is accessible to everyone.
               /* .antMatchers("/test/**").permitAll()
                .antMatchers(HttpMethod.POST,"/user/").hasRole("ADMIN")
                .antMatchers(HttpMethod.GET,"/user/").hasRole("USER")
                .antMatchers("/role/**").hasRole("admin")
                .anyRequest().authenticated()*/
                .anyRequest().access("@rbacService.hasPermission(request,authentication)")
                //.anyRequest().access("")
                // Other URLs require authentication
                //.authenticated()
                .and()
                // login correlation
                // Open Logon
                .formLogin()
                // Successful login
                .successHandler(authenticationSuccessHandler)
                // Logon failure
                .failureHandler(authenticationFailureHandler)
                .permitAll()
                .and()
                // logout correlation
                .logout()
                .logoutSuccessHandler(logoutSuccessHandler)
                .addLogoutHandler(logoutHandler)
                .permitAll().and()
                // Remembering that I am relevant
                .rememberMe()
                .rememberMeParameter("remember-me").userDetailsService(selfUserDetailsService)
                .tokenRepository(persistentTokenRepository())
                .tokenValiditySeconds(6000);
                // No access to data in JSON format
                http.exceptionHandling().accessDeniedHandler(accessDeniedHandler);
    }

Now the function is basically available, just need to improve the status of each return result can be used.

6. Remember me, remember my function Remeber me

	@Autowired
    DataSource dataSource;
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }

Add in config

  	.rememberMe()
    .rememberMeParameter("remember-me").userDetailsService(selfUserDetailsService)
    .tokenRepository(persistentTokenRepository())
demo git address: Portal

Welcome to review, improve and supplement, point out the shortcomings, thank you.

Keywords: JSON git

Added by jakem on Fri, 06 Sep 2019 15:03:29 +0300