spring-security实战

项目架构:spring-boot+spring-security+thymeleafcss

1.导包(bootthymeleaf的包请自行导入,版本号我抽的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.核心配置类(完整代码最后放出)web

2.1自定义security的配置类,而后继承WebSecurityConfigurerAdapter这个抽象类。spring

2.2打上@EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true)这两个注解编程

2.3重写configure(HttpSecurity http)方法,使用链式编程使用http.formLogin()方法设置你须要的配置(拦截参数,登陆路径,跨域请求等)跨域

2.4重写configure(WebSecurity web)方法,释放静态资源session

 

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

 

2.5重写configure(AuthenticationManagerBuilder auth)方法,自定义你的登陆验证架构

loginAuthenticationProvider:这是自定义的登陆验证类,注入调用
customUserDetailsService:这是自定义的帐号存储类,注入调用
customPasswordEncoder:这是自定义的密码加密类,注入调用
loginAuthenticationProvider.setUserDetailsService(customUserDetailsService); loginAuthenticationProvider.setPasswordEncoder(customPasswordEncoder); auth.authenticationProvider(loginAuthenticationProvider); super.configure(auth);

3.security国际化问题框架

在使用security过程当中,由于原生代码中DaoAuthenticationProvider这个类的additionalAuthenticationChecks方法ide

会在你前端页面登录失败的时候返回Bad credentials这个消息。这会让系统看上去不那么友好。

解决方法是:

1.在resources文件夹中添加messages_zh_CN.properties这个文件。自定义你想返回前端的话。

2.自定义登陆验证类loginAuthenticationProvider(最后放出完整代码)

3.在自定义security的配置类中作相应配置

完整代码:

1.自定义security配置类

@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") // 指定登陆页面及成功后跳转页面
                .successForwardUrl("/loadIndex") .and().authorizeRequests() .antMatchers(commonProperties.getAllowList()) // 上述url全部用户均可访问(无需登陆)
 .permitAll() .and() .authorizeRequests() .anyRequest() // 除上面以外的都须要登陆
 .authenticated() .and() .logout() // 指定登出url
                .logoutUrl("/doLogout") .invalidateHttpSession(true) .and() .headers() .frameOptions() // frame框架
 .sameOrigin() // csrf跨域保护忽略特殊url
 .and().csrf().ignoringAntMatchers(commonProperties.getAllowList()); } /** * 静态资源放行 * @param web */ @Override public void configure(WebSecurity web) { //静态资源过滤
        web.ignoring().antMatchers("/**/*.js", "/**/*.css", "/**/*.png", "/**/*.jpg", "/**/*.gif", "/**/*.map"); } /** * 自定义认证方法 * @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.自定义帐号存储类

@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 public UserDetails loadUserByUsername(String username) { try{ Assert.isTrue(StringUtils.isNotBlank(username),"用户或密码错误,请从新输入"); // 经过用户名获取用户详细信息,构造权限
            UserDTO userInfo = authTokenService.getUserDetail(username); ResourceBO resource = userInfo.getResource(); List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); if(resource != null){ buildAuth(resource, authorities); } return new UserBO(userInfo, authorities); }catch (IllegalArgumentException e){ throw new UsernameNotFoundException("用户或密码错误,请从新输入"); }catch (Exception e){ log.error("获取用户信息异常",e); throw new UsernameNotFoundException("用户或密码错误,请从新输入"); } } }

3.自定义密码加密类

@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.自定义security认证

@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")); } } }
相关文章
相关标签/搜索