spring-security combat

Project architecture: the Spring the Spring-Security-the Boot + + Thymeleaf

1. The lead pack ( the Boot and thymeleaf import your own package, version number, I smoked the Properties )

 

<dependency>
         <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
 </dependency>

 

2. Core configuration class (complete code of the last release)

2.1 custom security configuration class, then inherit WebSecurityConfigurerAdapter this abstract class.

2.2 marked @EnableWebSecurity @EnableGlobalMethodSecurity (prePostEnabled = to true) these two notes

2.3 Rewrite configure (HttpSecurity http) method, using a chain programming using http.formLogin () method to set configuration (intercept parameter, log path, cross-domain requests, etc.) you need

2.4 Rewrite configure (WebSecurity web) method, the release of static resources

 

web.ignoring().antMatchers("/**/*.js", "/**/*.css", "/**/*.png", "/**/*.jpg", "/**/*.gif", "/**/*.map");

 

2.5 Rewrite configure (AuthenticationManagerBuilder auth) method, customize your login verification

loginAuthenticationProvider : this is a custom login validation class, into the call
customUserDetailsService : this is a custom account storage class, into the call
customPasswordEncoder : This is the password encryption class definition, calling injection
loginAuthenticationProvider.setUserDetailsService(customUserDetailsService);
loginAuthenticationProvider.setPasswordEncoder(customPasswordEncoder);
auth.authenticationProvider(loginAuthenticationProvider);
super.configure(auth);

3.security international issues

With security process, because the native code methods of this class DaoAuthenticationProvider additionalAuthenticationChecks

In return you will fail when the front landing page Bad credentials news. This causes the system does not look so friendly.

The solution is:

1. Add messages_zh_CN.properties this file in the resources folder. Customize the front if you want to return.

2. Customize login validation class loginAuthenticationProvider (last release the complete code)

3. configured accordingly in the custom class security configuration

Complete code:

1. Custom security configuration class

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final CustomPasswordEncoder customPasswordEncoder;
    private final CustomUserDetailsService customUserDetailsService;
    private final CommonProperties commonProperties;

    @Autowired
    public SecurityConfiguration(CustomPasswordEncoder customPasswordEncoder, CustomUserDetailsService customUserDetailsService, CommonProperties commonProperties) {
        this.customPasswordEncoder = customPasswordEncoder;
        this.customUserDetailsService = customUserDetailsService;
        this.commonProperties = commonProperties;
    }

    @Autowired
    private LoginAuthenticationProvider loginAuthenticationProvider;

    /**
     * http配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/login")
                .loginProcessingUrl ( )"/ doLogin" )
                 // specify the login page and successfully jump page 
                .successForwardUrl ( "/ loadIndex" ) 
                .AND (). authorizeRequests () 
                .antMatchers (commonProperties.getAllowList ()) 
                // above url accessible to all users (without logging in) 
                .permitAll () 
                .AND () 
                .authorizeRequests () 
                .anyRequest () 
                // will need to log in addition to the above 
                .authenticated () 
                .AND () 
                .logout () 
                // specify the logout url 
                .logoutUrl ( "/ doLogout" )
                .invalidateHttpSession ( to true 
                .AND () 
                .headers () 
                .frameOptions () 
                // Frame frame 
                .sameOrigin ()
                 // CSRF protection ignore the special cross-domain url 
                .AND (). CSRF (). ignoringAntMatchers (commonProperties.getAllowList ()) ; 
    } 

    / ** 
     * static resource release 
     * @param Web
      * / 
    @Override 
    public  void Configure (WebSecurity Web) {
         // static resource filter 
        web.ignoring () antMatchers ( "/ ** / * js.", "/. ** / *. css "," /**/*.png "," /**/*.jpg "," /**/*.gif "," /**/*.map "); /**/*.jpg "," /**/*.gif "," /**/*.map "
    } 

    / ** 
     * custom authentication methods 
     *@param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        loginAuthenticationProvider.setUserDetailsService(customUserDetailsService);
        loginAuthenticationProvider.setPasswordEncoder(customPasswordEncoder);
        auth.authenticationProvider(loginAuthenticationProvider);
        super.configure(auth);
    }

    /**
     * 自定义认证管理类
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 自定义密码加密类
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

}

2. Custom account storage class

@Service
public class CustomUserDetailsService implements UserDetailsService {
    private final AuthTokenService authTokenService;
    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    public CustomUserDetailsService(AuthTokenService authTokenService) {
        this.authTokenService = authTokenService;
    }

    /**
     * 将用户详细信息放入security session中
     * @param username
     * @return
     */
    @Override
    publicLoadUserByUsername UserDetails (username String) {
         the try { 
            Assert.IsTrue (StringUtils.isNotBlank (username), 'user or password is incorrect, please re-enter " );
             // get user details by user name, permission is constructed 
            UserDTO userInfo = authTokenService.getUserDetail (username); 
            ResourceBO Resource = userInfo.getResource (); 
            List <the GrantedAuthority> Authorities = new new the ArrayList <the GrantedAuthority> ();
             IF (Resource =! null ) { 
                buildAuth (Resource, Authorities); 
            } 
            return  new newUserBO (the userInfo, Authorities); 
        } the catch (an IllegalArgumentException E) {
             the throw  new new UsernameNotFoundException ( "User or password, please re-enter" ); 
        } the catch (Exception E) { 
            log.error ( "user information acquiring abnormal" , E) ;
             the throw  new new UsernameNotFoundException ( "user or password, please re-enter" ); 
        } 
    } 
}

3. custom password encryption class

@Service
public class CustomPasswordEncoder implements PasswordEncoder {
    @Override
    public String encode(CharSequence charSequence) {
        return charSequence.toString();
    }

    @Override
    public boolean matches(CharSequence charSequence, String s) {
        return s.equals(encode(charSequence));
    }
}

4. custom security authentication class

@Component
public class LoginAuthenticationProvider extends DaoAuthenticationProvider {

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Autowired
    private CustomPasswordEncoder customPasswordEncoder;

    @Autowired
    private void setJdbcUserDetailsService() {
        setUserDetailsService(customUserDetailsService);
    }

    /**
     * 自定义security国际化
     */
    @PostConstruct
    public void initProvider() {
        ReloadableResourceBundleMessageSource localMessageSource = new ReloadableResourceBundleMessageSource();
        localMessageSource.setBasenames("messages_zh_CN");
        messages = new MessageSourceAccessor(localMessageSource);
    }

    /**
     * 复写认证失败方法
     * @param userDetails
     * @param authentication
     * @throws AuthenticationException
     */
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            logger.debug("Authentication failed: no credentials provided");
            throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        }
        String presentedPassword = authentication.getCredentials().toString();
        if (!customPasswordEncoder.matches(presentedPassword, userDetails.getPassword())) {
            logger.debug("Authentication failed: password does not match stored value");
            throw new BadCredentialsException(messages.getMessage("AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
        }
    }
}

 

Guess you like

Origin www.cnblogs.com/kingofjava/p/11326089.html