spring security原理与实战

疯狂创客圈 Java 高并发【 亿级流量聊天室实战】实战系列 【博客园总入口

架构师成长+面试必备之 高并发基础书籍 【Netty Zookeeper Redis 高并发实战


疯狂创客圈 高并发 环境 视频,陆续上线:

  • Windows Redis 安装(带视频)
  • Linux Redis 安装(带视频)
  • Windows Zookeeper 安装(带视频)
  • Linux Zookeeper 安装(带视频)
  • RabbitMQ 离线安装(带视频)
  • Nacos 安装(带视频)
  • ElasticSearch 安装, 带视频**

小视频以及所需工具的百度网盘链接,请参见 疯狂创客圈 高并发社群 博客

Spring Security 的重要性

在web应用开发中,安全无疑是十分重要的,选择Spring Security来保护web应用是一个非常好的选择。Spring Security 是spring项目之中的一个安全模块,特别是在spring boot项目中,spring security已经默认集成和启动了。

Spring Security 默认为自动开启的,可见其重要性。

如果要关闭,需要在启动类加上,exclude ={SecurityAutoConfiguration} 的配置

@EnableEurekaClient
@SpringBootApplication(scanBasePackages = {
        "com.crazymaker.springcloud.user",
        "com.crazymaker.springcloud.seckill.remote.fallback",
        "com.crazymaker.springcloud.standard"
}, exclude = {SecurityAutoConfiguration.class})

或者

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration

一般不建议关闭。

Spring Security 核心组件

spring security核心组件有:Userdetails 、Authentication,UserDetailsService、AuthenticationProvider、AuthenticationManager 下面分别介绍。

Authentication

authentication 直译过来是“认证”的意思,在Spring Security 中Authentication用来表示当前用户是谁,一般来讲你可以理解为authentication就是一组用户名密码信息。Authentication也是一个接口,其定义如下:

public interface Authentication extends Principal, Serializable {

Collection<? extends GrantedAuthority> getAuthorities();
Object getCredentials();
Object getDetails();
Object getPrincipal();
boolean isAuthenticated();
void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
}

接口有4个get方法,分别获取

  • Authorities, 填充的是用户角色信息。

  • Credentials,直译,证书。填充的是密码。

  • Details ,用户信息。

  • Principal 直译,形容词是“主要的,最重要的”,名词是“负责人,资本,本金”。感觉很别扭,所以,还是不翻译了,直接用原词principal来表示这个概念,其填充的是用户名。
    因此可以推断其实现类有这4个属性。

这几个方法作用如下:

  • getAuthorities: 获取用户权限,一般情况下获取到的是用户的角色信息。

  • getCredentials: 获取证明用户认证的信息,通常情况下获取到的是密码等信息。

  • getDetails: 获取用户的额外信息,(这部分信息可以是我们的用户表中的信息)

  • getPrincipal: 获取用户身份信息,在未认证的情况下获取到的是用户名,在已认证的情况下获取到的是 UserDetails (UserDetails也是一个接口,里边的方法有getUsername,getPassword等)。

  • isAuthenticated: 获取当前 Authentication 是否已认证。

  • setAuthenticated: 设置当前 Authentication 是否已认证(true or false)。

UserDetails

UserDetails,看命知义,是用户信息的意思。其存储的就是用户信息,其定义如下:

public interface UserDetails extends Serializable {

Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
}

方法含义如下:

  • getAuthorites:获取用户权限,本质上是用户的角色信息。

  • getPassword: 获取密码。

  • getUserName: 获取用户名。

  • isAccountNonExpired: 账户是否过期。

  • isAccountNonLocked: 账户是否被锁定。

  • isCredentialsNonExpired: 密码是否过期。

  • isEnabled: 账户是否可用。

UserDetailsService

提到了UserDetails就必须得提到UserDetailsService, UserDetailsService也是一个接口,且只有一个方法loadUserByUsername,他可以用来获取UserDetails。


package org.springframework.security.core.userdetails;

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

通常在spring security应用中,我们会自定义一个CustomUserDetailsService来实现UserDetailsService接口,并实现其public UserDetails loadUserByUsername(final String login);方法。我们在实现loadUserByUsername方法的时候,就可以通过查询数据库(或者是缓存、或者是其他的存储形式)来获取用户信息,然后组装成一个UserDetails,(通常是一个org.springframework.security.core.userdetails.User,它继承自UserDetails) 并返回。

在实现loadUserByUsername方法的时候,如果我们通过查库没有查到相关记录,需要抛出一个异常来告诉spring security来“善后”。这个异常是org.springframework.security.core.userdetails.UsernameNotFoundException。

AuthenticationProvider

负责真正的验证。

当我们使用 authentication-provider 元素来定义一个 AuthenticationProvider 时,如果没有指定对应关联的 AuthenticationProvider 对象,Spring Security 默认会使用 DaoAuthenticationProvider。DaoAuthenticationProvider 在进行认证的时候需要一个 UserDetailsService 来获取用户的信息 UserDetails,其中包括用户名、密码和所拥有的权限等。所以如果我们需要改变认证的方式,我们可以实现自己的 AuthenticationProvider;如果需要改变认证的用户信息来源,我们可以实现 UserDetailsService。

实现了自己的 AuthenticationProvider 之后,我们可以在配置文件中这样配置来使用我们自己的 AuthenticationProvider。其中 myAuthenticationProvider 就是我们自己的 AuthenticationProvider 实现类对应的 bean。

AuthenticationProvider 接口如下:

package org.springframework.security.authentication;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

public interface AuthenticationProvider {
    Authentication authenticate(Authentication var1) throws AuthenticationException;

    boolean supports(Class<?> var1);
}

  • authenticate 表示认证的动作。

  • supports 表示所支持的 Authentication类型。Authentication 包含很多子类,如果 AbstractAuthenticationToken 。

AbstractAuthenticationToken implements Authentication

还有,可以自定义 Authentication ,比如 本实例所使用的: JwtAuthenticationToken。

AuthenticationManager

认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider。AuthenticationManager 中可以定义有多个 AuthenticationProvider。

AuthenticationManager 是一个接口,它只有一个方法,接收参数为Authentication,其定义如下:

public interface AuthenticationManager {
    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;
}

AuthenticationManager 的作用就是校验Authentication,如果验证失败会抛出AuthenticationException异常。AuthenticationException是一个抽象类,因此代码逻辑并不能实例化一个AuthenticationException异常并抛出,实际上抛出的异常通常是其实现类,如DisabledException,LockedException,BadCredentialsException等。BadCredentialsException可能会比较常见,即密码错误的时候。

组件比较多,但是如果主要流程理顺了,也比较简单。

Spring Security 实战

搞定两个 AuthenticationProvider:

(1) 从数据库获取用户

首先通过 UserDetailsService 获取 UserDetails,然后 通过 UserDetailsService 装配 DaoAuthenticationProvider

(2) 完成用户的认证

实现一个自己的 JwtAuthenticationProvider,完成用户的认证

(3)定制一个过滤器

(4)完成所有组件的装配

实战1 : UserDetailsService 获取 UserDetails

首先通过 UserDetailsService 获取 UserDetails,然后 通过 UserDetailsService 装配 DaoAuthenticationProvider。

package com.crazymaker.springcloud.user.info.service.impl;

@Slf4j
@Service
public class UserAuthService implements UserDetailsService {

    private PasswordEncoder passwordEncoder;

    public UserAuthService() {
        //默认使用 bcrypt, strength=10
        this.passwordEncoder =
                PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }


    private UserPO loadFromDB(String username) {
        if (null == userDao)

        {
            userDao = CustomAppContext.getBean(UserDao.class);
        }

        List<UserPO> list = userDao.findAllByLoginName(username);

        if (null == list || list.size() <= 0) {
            return null;
        }
        UserPO userPO = list.get(0);
        return userPO;
    }

 

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {


        UserPO userPO = loadFromDB(username);


        //将salt放到password字段返回
        return User.builder()
                .username(userPO.getLoginName())
                .password(userPO.getPassword())
//                .password(SessionConstants.SALT)
                //BCrypt.gensalt();  正式开发时可以调用该方法实时生成加密的salt
//                .password(SessionConstants.SALT)
                .authorities(SessionConstants.USER_INFO)
                .roles("USER")
                .build();

    }


}

实战2: 装配 DaoAuthenticationProvider

在 SecurityConfiguration 配置类中加入如下内容:


    @Bean("daoAuthenticationProvider")
    protected AuthenticationProvider daoAuthenticationProvider() throws Exception {
        //这里会默认使用BCryptPasswordEncoder比对加密后的密码,注意要跟createUser时保持一致
        DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
        daoProvider.setUserDetailsService(userDetailsService());
        return daoProvider;
    }


    @Override
    protected UserDetailsService userDetailsService() {
        return new UserAuthService();
    }

实战3: 实现一个自己的 JwtAuthenticationProvider

继承于 AuthenticationProvider,实现一个自己的 JwtAuthenticationProvider,完成用户的认证

package com.crazymaker.springcloud.standard.security.provider;
//...

public class JwtAuthenticationProvider implements AuthenticationProvider {

    private RedisOperationsSessionRepository sessionRepository;
    private CustomedSessionIdResolver httpSessionIdResolver;

    public JwtAuthenticationProvider(RedisOperationsSessionRepository sessionRepository,
                                     CustomedSessionIdResolver httpSessionIdResolver) {
        this.sessionRepository = sessionRepository;
        this.httpSessionIdResolver = httpSessionIdResolver;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        DecodedJWT jwt = ((JwtAuthenticationToken) authentication).getToken();
        if (jwt.getExpiresAt().before(Calendar.getInstance().getTime())) {
            throw new NonceExpiredException("认证过期");
        }
        String sid = jwt.getSubject();
        String otoken = jwt.getToken();


        Session session = null;

        try {
            session = sessionRepository.findById(sid);
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (null == session) {
            throw new NonceExpiredException("认证有误,请重新登录");
        }

        String json = session.getAttribute(G_USER);
        if (StringUtils.isBlank(json)) {
            throw new NonceExpiredException("认证有误,请重新登录");
        }

        UserDTO userDTO = JsonUtil.jsonToPojo(json, UserDTO.class);
        if (null == userDTO) {
            throw new NonceExpiredException("认证有误");
        }


        String password = userDTO.getPassword();

        String username = userDTO.getLoginName();
        UserDetails user = User.builder()
                .username(username)
                .password(password)
                .authorities(SessionConstants.USER_INFO)
                .build();

        String encryptSalt = password;
        try {
            Algorithm algorithm = Algorithm.HMAC256(encryptSalt);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withSubject(sid).build();
            verifier.verify(jwt.getToken());
        } catch (Exception e) {
            throw new BadCredentialsException("JWT token verify fail", e);
        }
        JwtAuthenticationToken token =
                new JwtAuthenticationToken(user, jwt, user.getAuthorities());
        return token;
    }


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

}

实战4: 装配 AuthenticationManager

认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider。AuthenticationManager 中可以定义有多个 AuthenticationProvider。

  @EnableWebSecurity()
public class UserWebSecurityConfig extends WebSecurityConfigurerAdapter {
  
  @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(daoAuthenticationProvider())
                .authenticationProvider(jwtAuthenticationProvider());
    }
    //....

}

实战5: 定制过滤器,将 AuthenticationManager 用起来

搞得再多,如果不通过过滤器,将 AuthenticationManager 用起来,也是没有用的。

package com.crazymaker.springcloud.standard.security.filter;
//.....

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private RequestMatcher requiresAuthenticationRequestMatcher;
    private List<RequestMatcher> permissiveRequestMatchers;
    private AuthenticationManager authenticationManager;


    private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
    private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();

     //.....
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        Authentication authResult = null;
        /**
         * 场景: 从 zuul 过来,直接带上session 头
         */
        if (StringUtils.isNotEmpty(request.getHeader(SessionConstants.SESSION_SEED))) {
            request.setAttribute(SessionConstants.SESSION_SEED,
                    request.getHeader(SessionConstants.SESSION_SEED));
            UserDetails userDetails = User.builder()
                    .username(request.getHeader(SessionConstants.SESSION_SEED))
                    .password(request.getHeader(SessionConstants.SESSION_SEED))
                    .authorities(SessionConstants.USER_INFO)
                    .build();
            authResult = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
            successfulAuthentication(request, response, filterChain, authResult);

            filterChain.doFilter(request, response);
            return;
        }

        /**
         * 正常场景: 单体微服务访问,或者从Zuul过来,没有带 session head
         */
        if (!requiresAuthentication(request, response)) {

            filterChain.doFilter(request, response);
            return;
        }
        AuthenticationException failed = null;
        try {
            String token = getJwtToken(request);
            if (StringUtils.isNotBlank(token)) {
                JwtAuthenticationToken authToken = new JwtAuthenticationToken(JWT.decode(token));
                DecodedJWT jwt = authToken.getToken();
                
                //将  AuthenticationManager 用起来
                authResult = this.getAuthenticationManager().authenticate(authToken);
                UserDetails user = (UserDetails) authResult.getPrincipal();
                request.setAttribute(SessionConstants.SESSION_SEED, jwt.getSubject());
            } else {
                failed = new InsufficientAuthenticationException("请求头认证消息为空");
            }
        } catch (JWTDecodeException e) {
            logger.error("JWT format error", e);
            failed = new InsufficientAuthenticationException("请求头认证消息格式错误", failed);
        } catch (InternalAuthenticationServiceException e) {
            logger.error(
                    "An internal error occurred while trying to authenticate the user.",
                    failed);
            failed = e;
        } catch (AuthenticationException e) {
            // Authentication failed
            failed = e;
        }
        if (authResult != null) {
            successfulAuthentication(request, response, filterChain, authResult);
        } else if (!permissiveRequest(request)) {
            unsuccessfulAuthentication(request, response, failed);
            return;
        }

        filterChain.doFilter(request, response);
    }

    protected void unsuccessfulAuthentication(HttpServletRequest request,
                                              HttpServletResponse response, AuthenticationException failed)
            throws IOException, ServletException {
        SecurityContextHolder.clearContext();
        failureHandler.onAuthenticationFailure(request, response, failed);
    }

 //....

}

实战6: 配置 HttpSecurity 的过滤机制

还是在 UserWebSecurityConfig 配置文件,将 HttpSecurity 的过滤机制配置起来,完成所有组件的装配。

代码如下:

package com.crazymaker.springcloud.user.info.config;
//...

@EnableWebSecurity()
public class UserWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserAuthService userAuthService;


    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers(
                        "/v2/api-docs",
                        "/swagger-resources/configuration/ui",
                        "/swagger-resources",
                        "/swagger-resources/configuration/security",
                        "/swagger-ui.html",
                        "/api/user/login/v1",
//                        "/api/user/add/v1",
//                        "/api/user/speed/test/v1",
//                        "/api/user/say/hello/v1",
//                        "/api/user/*/detail/v1",
                        "/api/crazymaker/duty/info/user/login")
                .permitAll()
                .anyRequest().authenticated()

//                .antMatchers("/image/**").permitAll()
//                .antMatchers("/admin/**").hasAnyRole("ADMIN")
                .and()

                .formLogin().disable()
                .sessionManagement().disable()
                .cors()
                .and()

                .addFilterAfter(new OptionsRequestFilter(), CorsFilter.class)
                .apply(new JsonLoginConfigurer<>()).loginSuccessHandler(jsonLoginSuccessHandler())
                .and()
                .apply(new JwtAuthConfigurer<>()).tokenValidSuccessHandler(jwtRefreshSuccessHandler()).permissiveRequestUrls("/logout")
                .and()
                .logout()
//		        .logoutUrl("/logout")   //默认就是"/logout"
                .addLogoutHandler(tokenClearLogoutHandler())
                .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
                .and()
                .addFilterBefore(springSessionRepositoryFilter(), SessionManagementFilter.class)
                .sessionManagement().disable()
        ;


    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/api/user/login/v1",
                "/v2/api-docs",
                "/swagger-resources/configuration/ui",
                "/swagger-resources",
                "/swagger-resources/configuration/security",
//                "/api/user/say/hello/v1",
//                "/api/user/add/v1",
//                "/api/user/speed/test/v1",
//                "/api/user/*/detail/v1",
                "/images/**",
                "/swagger-ui.html",
                "/webjars/**",
                "**/favicon.ico",
                "/css/**",
                "/js/**",
                "/api/crazymaker/info/user/login"
        );

    }


    @Resource
    RedisOperationsSessionRepository sessionRepository;

    @Resource
    public CustomedSessionIdResolver httpSessionIdResolver;

    @DependsOn({"sessionRepository", "httpSessionIdResolver"})
    @Bean("jwtAuthenticationProvider")
    protected AuthenticationProvider jwtAuthenticationProvider() {
        return new JwtAuthenticationProvider(sessionRepository, httpSessionIdResolver);
    }


    public <S extends Session> OncePerRequestFilter springSessionRepositoryFilter() {

        CustomedSessionRepositoryFilter<? extends Session> sessionRepositoryFilter = new CustomedSessionRepositoryFilter<>(
                sessionRepository);
//        sessionRepositoryFilter.setServletContext(this.servletContext);
        sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);
        return sessionRepositoryFilter;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(daoAuthenticationProvider())
                .authenticationProvider(jwtAuthenticationProvider());
    }


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


    @Bean("daoAuthenticationProvider")
    protected AuthenticationProvider daoAuthenticationProvider() throws Exception {
        //这里会默认使用BCryptPasswordEncoder比对加密后的密码,注意要跟createUser时保持一致
        DaoAuthenticationProvider daoProvider = new DaoAuthenticationProvider();
        daoProvider.setUserDetailsService(userDetailsService());
        return daoProvider;
    }


    @Bean
    protected JwtRefreshSuccessHandler jwtRefreshSuccessHandler() {
        return new JwtRefreshSuccessHandler();
    }


    @Override
    protected UserDetailsService userDetailsService() {
        return new UserAuthService();
    }


    @Bean
    protected JsonLoginSuccessHandler jsonLoginSuccessHandler() {
        return new JsonLoginSuccessHandler(userAuthService);
    }


    @Bean
    protected TokenClearLogoutHandler tokenClearLogoutHandler() {
        return new TokenClearLogoutHandler(userAuthService);
    }

    @Bean
    protected CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "HEAD", "OPTION"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.addExposedHeader(SessionConstants.AUTHORIZATION);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}

实战小结

大概通过以上6步,一个集成jwt的springsecurity机制,完整的配置起来了。

具体,请关注 Java 高并发研习社群博客园 总入口


最后,介绍一下疯狂创客圈:疯狂创客圈,一个Java 高并发研习社群博客园 总入口

疯狂创客圈,倾力推出:面试必备 + 面试必备 + 面试必备 的基础原理+实战 书籍 《Netty Zookeeper Redis 高并发实战

img


疯狂创客圈 Java 死磕系列

  • Java (Netty) 聊天程序【 亿级流量】实战 开源项目实战

Java 面试题 一网打尽**


  • 4
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
序言 I. 入门 1. 介绍 1.1. Spring Security是什么? 1.2. 历史 1.3. 发行版本号 1.4. 获得Spring Security 1.4.1. 项目模块 1.4.1.1. Core - spring-security-core.jar 1.4.1.2. Web - spring-security-web.jar 1.4.1.3. Config - spring-security-config.jar 1.4.1.4. LDAP - spring-security-ldap.jar 1.4.1.5. ACL - spring-security-acl.jar 1.4.1.6. CAS - spring-security-cas-client.jar 1.4.1.7. OpenID - spring-security-openid.jar 1.4.2. 获得源代码 2. Security命名空间配置 2.1. 介绍 2.1.1. 命名空间的设计 2.2. 开始使用安全命名空间配置 2.2.1. 配置web.xml 2.2.2. 最小 <http> 配置 2.2.2.1. auto-config 包含了什么? 2.2.2.2. 表单和基本登录选项 2.2.3. 使用其他认证提供器 2.2.3.1. 添加一个密码编码器 2.3. 高级web特性 2.3.1. Remember-Me认证 2.3.2. 添加HTTP/HTTPS信道安全 2.3.3. 会话管理 2.3.3.1. 检测超时 2.3.3.2. 同步会话控制 2.3.3.3. 防止Session固定攻击 2.3.4. 对OpenID的支持 2.3.4.1. 属性交换 2.3.5. 添加你自己的filter 2.3.5.1. 设置自定义 AuthenticationEntryPoint 2.4. 保护方法 2.4.1. <global-method-security> 元素 2.4.1.1. 使用protect-pointcut 添加安全切点 2.5. 默认的AccessDecisionManager 2.5.1. 自定义AccessDecisionManager 2.6. 验证管理器和命名空间 3. 示例程序 3.1. Tutorial示例 3.2. Contacts 3.3. LDAP例子 3.4. CAS例子 3.5. Pre-Authentication例子 4. Spring Security社区 4.1. 任务跟踪 4.2. 成为参与者 4.3. 更多信息 II. 结构和实现 5. 技术概述 5.1. 运行环境 5.2. 核心组件 5.2.1. SecurityContextHolder, SecurityContext 和 Authentication对象 5.2.1.1. 获得当前用户的信息 5.2.2. UserDetailsService 5.2.3. GrantedAuthority 5.2.4. 小结 5.3. 验证 5.3.1. 什么是Spring Security的验证呢? 5.3.2. 直接设置SecurityContextHolder的内容 5.4. 在web应用中验证 5.4.1. ExceptionTranslationFilter 5.4.2. AuthenticationEntryPoint 5.4.3. 验证机制 5.4.4. 在请求之间保存SecurityContext 。 5.5. Spring Security中的访问控制(验证) 5.5.1. 安全和AOP建议 5.5.2. 安全对象和AbstractSecurityInterceptor 5.5.2.1. 配置属性是什么? 5.5.2.2. RunAsManager 5.5.2.3. AfterInvocationManager 5.5.2.4. 扩展安全对象模型 5.6. 国际化 6. 核心服务 6.1. The AuthenticationManager , ProviderManager 和 AuthenticationProvider s 6.1.1. DaoAuthenticationProvider 6.2. UserDetailsService 实现 6.2.1. 内存认证 6.2.2. JdbcDaoImpl 6.2.2.1. 权限分组 6.3. 密码加密 6.3.1. 什么是散列加密? 6.3.2. 为散列加点儿盐 6.3.3. 散列和认证 III. web应用安全 7. 安全过滤器链 7.1. DelegatingFilterProxy 7.2. FilterChainProxy 7.2.1. 绕过过滤器链 7.3. 过滤器顺序 7.4. 使用其他过滤器 —— 基于框架 8. 核心安全过滤器 8.1. FilterSecurityInterceptor 8.2. ExceptionTranslationFilter 8.2.1. AuthenticationEntryPoint 8.2.2. AccessDeniedHandler 8.3. SecurityContextPersistenceFilter 8.3.1. SecurityContextRepository 8.4. UsernamePasswordAuthenticationFilter 8.4.1. 认证成功和失败的应用流程 9. Basic(基本)和Digest(摘要)验证 9.1. BasicAuthenticationFilter 9.1.1. 配置 9.2. DigestAuthenticationFilter 9.2.1. Configuration 10. Remember-Me认证 10.1. 概述 10.2. 简单基于散列标记的方法 10.3. 持久化标记方法 10.4. Remember-Me接口和实现 10.4.1. TokenBasedRememberMeServices 10.4.2. PersistentTokenBasedRememberMeServices 11. 会话管理 11.1. SessionManagementFilter 11.2. SessionAuthenticationStrategy 11.3. 同步会话 12. 匿名认证 12.1. 概述 12.2. 配置 12.3. AuthenticationTrustResolver IV. 授权 13. 验证架构 13.1. 验证 13.2. 处理预调用 13.2.1. AccessDecisionManager 13.2.2. 基于投票的AccessDecisionManager实现 13.2.2.1. RoleVoter 13.2.2.2. AuthenticatedVoter 13.2.2.3. Custom Voters 13.3. 处理后决定 14. 安全对象实现 14.1. AOP联盟 (MethodInvocation) 安全拦截器 14.1.1. 精确的 MethodSecurityIterceptor 配置 14.2. AspectJ (JoinPoint) 安全拦截器 15. 基于表达式的权限控制 15.1. 概述 15.1.1. 常用内建表达式 15.2. Web 安全表达式 15.3. 方法安全表达式 15.3.1. @Pre 和 @Post 注解 15.3.1.1. 访问控制使用 @PreAuthorize 和 @PostAuthorize 15.3.1.2. 过滤使用 @PreFilter 和 @PostFilter 16. acegi到spring security的转换方式 16.1. Spring Security是什么 16.2. 目标 16.3. 步骤 16.4. 总结 V. 高级话题 17. 领域对象安全(ACLs) 17.1. 概述 17.2. 关键概念 17.3. 开始 18. 预认证场景 18.1. 预认证框架类 18.1.1. AbstractPreAuthenticatedProcessingFilter 18.1.2. AbstractPreAuthenticatedAuthenticationDetailsSource 18.1.2.1. J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource 18.1.3. PreAuthenticatedAuthenticationProvider 18.1.4. Http403ForbiddenEntryPoint 18.2. 具体实现 18.2.1. 请求头认证(Siteminder) 18.2.1.1. Siteminder示例配置 18.2.2. J2EE容器认证 19. LDAP认证 19.1. 综述 19.2. 在Spring Security里使用LDAP 19.3. 配置LDAP服务器 19.3.1. 使用嵌入测试服务器 19.3.2. 使用绑定认证 19.3.3. 读取授权 19.4. 实现类 19.4.1. LdapAuthenticator实现 19.4.1.1. 常用功能 19.4.1.2. BindAuthenticator 19.4.1.3. PasswordComparisonAuthenticator 19.4.1.4. 活动目录认证 19.4.2. 链接到LDAP服务器 19.4.3. LDAP搜索对象 19.4.3.1. FilterBasedLdapUserSearch 19.4.4. LdapAuthoritiesPopulator 19.4.5. Spring Bean配置 19.4.6. LDAP属性和自定义UserDetails 20. JSP标签库 20.1. 声明Taglib 20.2. authorize 标签 20.3. authentication 标签 20.4. accesscontrollist 标签 21. Java认证和授权服务(JAAS)供应器 21.1. 概述 21.2. 配置 21.2.1. JAAS CallbackHandler 21.2.2. JAAS AuthorityGranter 22. CAS认证 22.1. 概述 22.2. CAS是如何工作的 22.3. 配置CAS客户端 23. X.509认证 23.1. 概述 23.2. 把X.509认证添加到你的web系统中 23.3. 为tomcat配置SSL 24. 替换验证身份 24.1. 概述 24.2. 配置 A. 安全数据库表结构 A.1. User表 A.1.1. 组权限 A.2. 持久登陆(Remember-Me)表 A.3. ACL表 A.3.1. Hypersonic SQL A.3.1.1. PostgreSQL B. 安全命名空间 B.1. Web应用安全 - <http> 元素 B.1.1. <http> 属性 B.1.1.1. servlet-api-provision B.1.1.2. path-type B.1.1.3. lowercase-comparisons B.1.1.4. realm B.1.1.5. entry-point-ref B.1.1.6. access-decision-manager-ref B.1.1.7. access-denied-page B.1.1.8. once-per-request B.1.1.9. create-session B.1.2. <access-denied-handler> B.1.3. <intercept-url> 元素 B.1.3.1. pattern B.1.3.2. method B.1.3.3. access B.1.3.4. requires-channel B.1.3.5. filters B.1.4. <port-mappings> 元素 B.1.5. <form-login> 元素 B.1.5.1. login-page B.1.5.2. login-processing-url B.1.5.3. default-target-url B.1.5.4. always-use-default-target B.1.5.5. authentication-failure-url B.1.5.6. authentication-success-handler-ref B.1.5.7. authentication-failure-handler-ref B.1.6. <http-basic> 元素 B.1.7. <remember-me> 元素 B.1.7.1. data-source-ref B.1.7.2. token-repository-ref B.1.7.3. services-ref B.1.7.4. token-repository-ref B.1.7.5. key 属性 B.1.7.6. token-validity-seconds B.1.7.7. user-service-ref B.1.8. <session-management> 元素 B.1.8.1. session-fixation-protection B.1.9. <concurrent-control> 元素 B.1.9.1. max-sessions 属性 B.1.9.2. expired-url 属性 B.1.9.3. error-if-maximum-exceeded 属性 B.1.9.4. session-registry-alias 和session-registry-ref 属性 B.1.10. <anonymous> 元素 B.1.11. <x509> 元素 B.1.11.1. subject-principal-regex 属性 B.1.11.2. user-service-ref 属性 B.1.12. <openid-login> 元素 B.1.13. <logout> 元素 B.1.13.1. logout-url 属性 B.1.13.2. logout-success-url 属性 B.1.13.3. invalidate-session 属性 B.1.14. <custom-filter> 元素 B.2. 认证服务 B.2.1. <authentication-manager> 元素 B.2.1.1. <authentication-provider>元素 B.2.1.2. 使用 <authentication-provider> 来引用一个 AuthenticationProvider Bean B.3. 方法安全 B.3.1. <global-method-security> 元素 B.3.1.1. secured-annotations 和jsr250-annotations 属性 B.3.1.2. 安全方法使用<protect-pointcut> B.3.1.3. <after-invocation-provider> 元素 B.3.2. LDAP命名空间选项 B.3.2.1. 使用<ldap-server> 元素定义LDAP服务器 B.3.2.2. <ldap-provider> 元素 B.3.2.3. <ldap-user-service> 元素

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值