今天是:
带着程序的旅程,每一行代码都是你前进的一步,每个错误都是你成长的机会,最终,你将抵达你的目的地。
title

Spring Security

1.Spring Security 能干什么

Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架。 Spring Security 是一个专注于为 Java 应用程序提供身份验证和授权的框架。 与所有 Spring 项目一样,Spring Security 的真正强大之处在于它可以轻松扩展以满足自定义要求

2.认证配置

@Configuration //springboot开启是扫描的类
@EnableWebSecurity//开启springsecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

}

@Configuration
@EnableWebSecurity //开启springsecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    SysUserService userService;

    @Override
    public void configure(WebSecurity web) {
        // 设置不拦截规则
        web.ignoring().antMatchers("/login", "/images/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/*", "/**").permitAll()
                .antMatchers("/**").authenticated()   // 指定所有的请求都需登录
                .anyRequest().authenticated()
                .and()
                .cors().and().csrf().disable()
                // 自定义登录页面
                .formLogin()
                .loginPage("/login")                        // 指定登录页面
                .loginProcessingUrl("/signin")                    // 执行登录操作的 URL
                .usernameParameter("username")                          // 用户请求登录提交的的用户名参数
                .passwordParameter("password")                          // 用户请求登录提交的密码参数
                .failureHandler(this.authenticationFailureHandler())    // 定义登录认证失败后执行的操作
                .successHandler(this.authenticationSuccessHandler());   // 定义登录认证曾工后执行的操作


        // 自定义注销
        http.logout().logoutUrl("/signout")                     // 执行注销操作的 URL
                .logoutSuccessUrl("/login")                             // 注销成功后跳转的页面
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID");
    }


    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("*"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    /**
     * 登录认证配置
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this.userDetailsService())
                .passwordEncoder(new BCryptPasswordEncoder());
    }

    /**
     * 使用自定义的登录密码加密规则,需继承  LLgRi7cWeUUu5zpB7dekZFapB2XdRCvM4N
     */
    @Bean(name = "myMessageDigestPasswordEncoder")
    public PasswordEncoder messageDigestPasswordEncoder() {
        return new MyMessageDigestPasswordEncoder("md5");

    }

    /**
     * 使用自定义的登录认证失败处理类,需继承 AuthenticationFailureHandler
     */
    @Bean(name = "authenticationFailureHandlerImpl")
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new AuthenticationFailureHandlerImpl();
    }

    /**
     * 使用自定义的登录认证成功处理类,需继承 AuthenticationSuccessHandler
     */
    @Bean(name = "authenticationSuccessHandlerImpl")
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new AuthenticationSuccessHandlerImpl();
    }


    @Bean(name = "userDetailsServiceImpl")
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    // 表达式控制器
    @Bean(name = "expressionHandler")
    public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
        return new DefaultWebSecurityExpressionHandler();
    }





    @Bean(BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}

配置之后当我们请求/login,提交表单表单的中用户名和密码的name 时username和password,spring 会拦截并校验用户名和密码。

UserDetailsService是查询数据库中的用户和用户所对应的角色

 

public class UserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private SysUserService sysUserService;

    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private SysRoleService sysRoleService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (StringUtils.isEmpty(username)) {
            throw new BadCredentialsException("用户名不能为空");
        }

        UserDetails userDetails = null;
        // 根据用户名从数据库查询用户信息,根据自己的业务规则去写
        SysUser user = (SysUser) sysUserService.findByUserName(username);
        if (user == null) {
            throw new BadCredentialsException("用户名不存在");
        }
        //获取用户角色列表
        List<SysUserRole> surList = sysUserRoleService.getUserRoleByUserId(user.getId());
        String roles = "";
        for (SysUserRole sur : surList) {
            SysRole sr = (SysRole) sysRoleService.findById(sur.getRoleId());
            roles += "ROLE_" + sr.getRole() + ",";
        }
        List<GrantedAuthority> grantedAuthorityList = AuthorityUtils.createAuthorityList(roles.substring(0, roles.length() - 1));
        userDetails = new User(user.getUsername(), user.getPassword(), // 数据库中存储的密码
                true,               // 用户是否激活
                true,               // 帐户是否过期
                true,               // 证书是否过期
                true,               // 账号是否锁定
                grantedAuthorityList);  // 用户角色列表,必须以 ROLE_ 开头
        return userDetails;
    }

这样当校验成功或失败后security 将吧控制权交到 AuthenticationSuccessHandler,AuthenticationFailureHandler。我们可以实现个类做成功或失败的处理

3.资源访问控制

假设有个列表页面,操作权限要分给不同的人。后端可以使用注解,前端可以使用springsecurity标签

@EnableGlobalMethodSecurity(prePostEnabled=true)
@PreAuthorize("hasAuthority('list')")
<sec:authorize access="hasAuthority('addArticle')"></sec>

 

引用文档

https://docs.spring.io/spring-security/reference/servlet/architecture.html

分享到:

专栏

类型标签

网站访问总量