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 高并发实战


疯狂创客圈 Java 死磕系列

  • Java (Netty) 聊天程序【 亿级流量】实战 开源项目实战
  • Netty 源码、原理、JAVA NIO 原理
  • Java 面试题 一网打尽
  • 疯狂创客圈 【 博客园 总入口 】

Java 面试题 一网打尽**



spring security 原理+实战

原文地址:https://www.cnblogs.com/crazymakercircle/p/12040402.html

时间: 2024-10-30 06:06:03

spring security 原理+实战的相关文章

Spring Security原理与应用

Spring Security是什么 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean(注:包括认证与权限获取.配置.处理相关实例),充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)(注:代理增强类)功能,为应用系统提供声明式的安全访问控制功能,减少了

springboot学习总结(九)Spring security原理浅谈

认证是由 AuthenticationManager 来管理的,但是真正进行认证的是 AuthenticationManager 中定义的 AuthenticationProvider.AuthenticationManager 中可以定义有多个 AuthenticationProvider.当我们使用 authentication-provider 元素来定义一个 AuthenticationProvider 时,如果没有指定对应关联的 AuthenticationProvider 对象,Sp

Spring Security原理

Spring Security(六)—SpringSecurityFilterChain加载流程深度解析 https://cloud.tencent.com/developer/article/1164113 SpringSecurity 源码分析之SecurityFilterchain的构建 https://blog.csdn.net/mingtiandexia/article/details/88880057 Spring Security(六)—SpringSecurityFilterCh

Spring Security编程模型

1.采用spring进行权限控制 url权限控制 method权限控制 实现:aop或者拦截器(本质就是之前之后进行控制)--------------------proxy就是 2.权限模型: 本质理论: RABC权限模型(可以参看这方面的理论研究,有充分的数学理论作支撑) =========================== 用户---名称,密码,备注 角色---角色名称 操作(权限)---添加,浏览---------------------(url,按钮,页签) 资源---人力资源库, =

springboot集成spring security实现restful风格的登录认证 附代码

一.文章简介 本文简要介绍了spring security的基本原理和实现,并基于springboot整合了spring security实现了基于数据库管理的用户的登录和登出,登录过程实现了验证码的校验功能. 完整代码地址:https://github.com/Dreamshf/spring-security.git 二.spring security框架简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.主要包括:用户认证

Spring Security 入门原理及实战

参考博客: https://www.cnblogs.com/demingblog/p/10874753.html Spring Security 是spring项目之中的一个安全模块,可以非常方便与spring项目无缝集成. 特别是在spring boot项目中加入spring security更是十分简单, 这里就简单介绍一下入门案例和使用原理吧! 写一个简单的springboot测试例子: @Controller public class AppController { @RequestMa

[转]spring security的原理及教程

Authentication:认证     spring security使用分类: 如何使用spring security,相信百度过的都知道,总共有四种用法,从简到深为:1.不用数据库,全部数据写在配置文件,这个也是官方文档里面的demo:2.使用 数据库,根据spring security默认实现代码设计数据库,也就是说数据库已经固定了,这种方法不灵活,而且那个数据库设计得很简陋,实用性差:3.spring security和Acegi不同,它不能修改默认filter了,但支持插入filt

spring security使用和原理简析(1)

主要参考:https://blog.csdn.net/u012373815/article/details/55225079 源码参考:https://github.com/527515025/springBoot 项目需求 1:实现了用户.角色.权限的动态管理,可以管控到接口地址,已经访问方式(get,post) 2:自定义登录接口 3:结合spring-session,来保存用户登录信息 表结构说明 method来控制相同方法名的不同访问方式(get,post,put等) 项目结构 废话不多

spring security使用和原理简析(2)

转自https://pjmike.github.io/2018/10/12/%E6%B5%85%E6%9E%90Spring-Security-%E6%A0%B8%E5%BF%83%E7%BB%84%E4%BB%B6/ 上一篇我们主要讲述了如何搭项目,这里我们就来简单探究一下原理 Spring Security的核心类 Spring Security的核心类主要包括以下几个: SecurityContextHolder: 存放身份信息的容器 Authentication: 身份信息的抽象接口 A