Spring security学习

文章详细介绍了SpringBoot项目中引入SpringSecurity后,如何处理登录、密码加密、自定义登录页面和登录逻辑,以及权限控制、记住我功能、CSRF防护。同时,提到了OAuth2授权和JWT的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. springboot web项目都能正常跳转(引入security启动依赖前)

  2. 引入spring-boot-starter-security,

    • 全都访问不了了,包括home.html静态资源也访问不了,全部都重定向到http://localhost:8080/login security自己默认的登录页;

    • 输入登录名和密码: user(默认) 密码(会输出在控制台),登录成功

    • UserDetailsService 接口

      • 唯一方法: 根据用户名, 返回UserDetails用户信息对象
        UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
      • 实现逻辑: 根据用户名到数据库去查询用户,
        如果没查到,应该手动抛出UsernameNotFoundException;
        如果查到了,应该比对用户传过来的密码和数据库的密码
    • UserDetails 接口

      • String getUsername();

      • String getPassword();

      • Collection<? extends GrantedAuthority> getAuthorities();

      • boolean isAccountNonExpired();

      • boolean isAccountNonLocked();

      • boolean isCredentialsNonExpired();

      • boolean isEnabled();

      • security框架提供了实现类 User
        public User(String username,
        String password,
        boolean enabled,
        boolean accountNonExpired,
        boolean credentialsNonExpired,
        boolean accountNonLocked,
        Collection<? extends GrantedAuthority> authorities)

    • PasswordEncoder 密码解析器

      • String encode(CharSequence rawPassword); // 加密密码

      • boolean matches(CharSequence rawPassword, String encodedPassword); // 匹配密码

      • BCryptPasswordEncoder 接口实现(推荐)

        • 加密/匹配密码 生成盐逻辑 参考: https://www.cnblogs.com/yangzhixue/p/12257885.html
  3. 自定义登录逻辑

    • 注入passwordEncoder,security就不会在控制台打印密码了
    • 在security的登录页输入用户名、密码,security将会自己调用UserDetailsService实现类对象的loadUserByUsername方法,
      返回UserDetails对象,然后做密码匹配,决定是否登录成功
    • (这里的是用的security自己的登录页面)
  4. 自定义登录页面和自定义登录成功或失败的处理逻辑

    • 继承WebSecurityConfigurerAdapter,重写configure(HttpSecurity http)方法,

      • 在此方法中配置自定义登录页面、自定义登录请求、放行登录请求、(以及关闭csrf否则走不了登录逻辑)、
        自定义登录表单提交用户名和密码、登录失败跳转、登录成功跳转

      • UsernamePasswordAuthenticationFilter 过滤器

        • 默认的表单提交名称: username & password

        • 限定了 /login post请求方式

        • 可配置,因为这个authFilter被FormLoginConfigurer所持有,可以设置这个过滤器

      • AuthenticationSuccessHandler 登录成功之后,自定义逻辑

        • 该接口中唯一方法: void onAuthenticationSuccess(HttpServletRequest request,
          HttpServletResponse response, Authentication authentication)
          throws IOException, ServletException;

          • Authentication 该方法回传了认证对象
            • 该接口中定义的方法

              • Collection<? extends GrantedAuthority> getAuthorities();
              • Object getCredentials();
              • Object getDetails();
              • Object getPrincipal();
              • boolean isAuthenticated();
              • void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
            • UsernamePasswordAuthenticationToken 作为Authentication的实现

              • User对象(UserDetailsService通过loadByUsername返回的UserDetails接口实现类对象)
              • authorities属性(list集合)
                • 其中元素为 SimpleGrantedAuthority
              • WebAuthenticationDetails对象
                • remoteAddress属性
                • sessionId属性
              • authenticated
                • 登陆成功,为true
      • AuthenticationFailureHandler 登录失败之后,自定义逻辑

        • 该接口中唯一方法: void onAuthenticationFailure(HttpServletRequest request,
          HttpServletResponse response, AuthenticationException exception)
          throws IOException, ServletException;
          • AuthenticationException 回传认证异常
  5. 访问控制

    • 公式:[url匹配规则.权限控制方法]

      • 注意配置顺序有影响
    • url匹配规则

      • .anyRequest().authenticated() 访问所有资源都需要授权

        • anyRequest 匹配所有请求
      • antMatcher

        • antMatchers(String… antPatterns)

          • 每个参数都是一个ant表达式,用于匹配url规则
          • ant匹配规则如下
            • ?: 匹配一个字符
            • *: 匹配0个或多个字符
            • **: 匹配0个或多个目录
          • 示例:
            • antMatchers(“/js/“,”/css/”).permitAll()
              • 放行js和css文件夹上下的所有资源
            • antMatchers(“/**/*.js”).permitAll()
              • 放行所有js文件
        • antMatchers(HttpMethod method, String… antPatterns)

      • regexMatchers

        • regexMatchers(String… regexPatterns)

          • 参数是正则表达式
          • 示例:
            • regexMatchers(“.+[.]js”).permitAll()
        • regexMatchers(HttpMethod method, String… antPatterns)

      • mvcMatchers
        .mvcMatchers(“img/**”).servletPath(“/v1”).permitAll

    • 权限控制方法

      • permitAll()

      • denyAll()

      • anonymous()

      • rememberMe()

      • authenticated()

      • fullyAuthenticated()

        • rememberMe无效,需要登录
      • hasRole(String role)

        • 这里的role参数不能以ROLE_打头,严格区分大小写;
        • 创建UserDetails对象的role角色时,要以Role_打头的字符串
      • hasAnyRole(String… roles)

      • hasAuthority(String authority)

      • hasAnyAuthority(String… authorities)

      • hasIpAddress(String ipaddressExpression)

    • 自定义因权限不足而拒绝访问时的处理逻辑

      • AccessDeniedHandler
        • 唯一方法: void handle(HttpServletRequest request, HttpServletResponse response,
          AccessDeniedException accessDeniedException) throws IOException,
          ServletException;
    • access自定义权限控制访问

      • 上面的权限控制都是基于access表达式

        • 如:
          • access(‘permitAll’) <==> .permitAll() [可以点进入方法,就可以看到]
          • access(“hasRole('ROLE_” + role + “')”) <==> .hasRole(String role) [从这里就可以看出为什么返回的User的authority要加‘ROLE_’前缀的原因了]
      • 自定义access权限控制方法

        • .antMatchers(“/access.html”).access(“@myAccessImpl.hasPermission(request,authentication)”)
        • 可以思考下,security已内置的实现,比如hasRole
          • 其实就是访问什么样的资源,需要什么样的权限,这个权限从userDetails对象中获取grantedAuthorities进行判断

6.基于注解访问控制
- 使用步骤
- 注解默认不可用,需要通过@EnableGlobalMethodSecurity开启后,并且启用对应的注解(比如securedEnabled=true),才能使用
- 如果设置的条件允许,程序正常执行。如果不允许,将会抛出异常AccessDeniedException
- 注解可以写到Service接口或方法上,也可以写道Controller或Controller方法上
- 注解
- @Secured
- 专门用于判断是否具有角色的,能写在类或方法上。参数要以ROLE_打头
- @PreAuthorize/@PostAuthorize
- 都是基于方法或类级别的注解
- @PreAuthorize 表示访问方法或类在执行之前先判断权限。
- 注解的参数和access()方法参数取值相同,都是权限表达式
- 可以写ROLE_打头,也可以不以ROLE_打头
- @PostAuthorize 表示访问方法或类在执行结束后判断权限
- 很少使用
- 再来补充一点
- 经过测试,在构造UserDetails对象时,传入给GrantedAuthority的字符串,
如果是以ROLE_打头的,那么这是个角色权限,否则是资源权限

7.记住我功能
- 使用步骤:
- 只需要在登录时,添加一个rememberMe的参数为true,spring security就会自动把用户存到数据源中,以后就可以不登陆进行访问了。默认2周
- 在security配置类中配置记住我的功能

8.thymeleaf模板权限控制
- 使用步骤:
- 导入thymeleaf对security的支持依赖
- (版本需要对应,否则无效且无报错,
比如这个项目导入的就是thymeleaf-extras-springsecurity4
而不是thymeleaf-extras-springsecurity5)
- 使用标签控制模板显示/隐藏

  1. 退出登录
    • 自定义退出登录url,以及退出登陆后重定向到的url(需要放行)

    • LogoutConfigurer

      • 默认添加了SecurityContextLogoutHandler,它是一个LogoutHandler

        • 它会销毁session会话对象
        • 它会销毁authentication认证对象
      • 可以自定义添加LogoutHandler

        • 通过 SecurityContextHolder 的静态方法获取当前登录用户认证对象
      • 也可以自定添加LogoutSuccessHandler

      • 退出登录,会把rememberMe存储的数据也给删掉

10.csrf
- Cross-site request forgery 跨站请求伪造。通过伪造用户请求访问受信任站点的非法请求访问。
- 跨域: 只要网络协议、ip地址、端口中任何一个不相同就是跨域请求
- 从spring security4开始CSRF防护默认开启。默认会拦截请求,进行csrf处理。csrf为了保证不是其它第3放网站访问,
要求访问时须携带参数名为_csrf值为token的内容(token由后端产生),如果token和服务端token匹配,则正常访问。
- 不关闭csrf,虽然可以正常登录,但是其它请求好像都有问题了(后面再看下什么原因)
- 应该是其它请求没有携带这个csrf的token
- 参考: https://blog.youkuaiyun.com/hanxiaotongtong/article/details/103451936

  1. Oauth2

    • Oauth是一个关于授权(authorization)的开放网络标准

      • 参考: http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
    • 授权模式

      • 参考: https://blog.youkuaiyun.com/bylfsj/article/details/102863842
      • 授权码模式(authorization code)
        • 授权码模式 是功能最完整,流程最严密 的授权模式
      • 简化模式(implicit)
      • 密码模式(resource owner password credentials)
        • 比较重要
      • 客户端模式(client credentials)
  2. spring security Oauth2架构

    • 参考: https://blog.youkuaiyun.com/tuyong1972873004/article/details/107257780
    • https://blog.youkuaiyun.com/lwd2307997664/article/details/115322334
  3. jwt

    • 由3部分组成: header.payload.signature
      • header包含了所使用的算法,

        • 是直接对头部json字符串进行一个Base64编码之后的一个字符串
      • payload包含了负载,可以自定义声明(claim),

        • 是直接对负载json字符串进行一个Base64编码之后的一个字符串
      • signature

        • 使用header编码之后的字符串 + payload编码之后的字符串 + 一个密钥 使用header指定的算法 生成
      • 最后使用.将以上3部分组合起来

        • header.payload.signature
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值