User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Spring   ›   SpringBoot   ›   正文
SpringBoot

SpringBoot—整合SpringSecurity(安全框架)

2020-04-10 01:55:07
899  0 0
参考目录 隐藏
1) 项目创建
2) 体验
3) 用户名配置
4) 配置文件配置用户名/密码
5) Java 配置用户名/密码
6) 登录配置
7) 忽略拦截

阅读完需:约 8 分钟

Spring Security 是 Spring 家族中的一个安全管理框架,实际上,在 Spring Boot 出现之前,Spring Security 就已经发展了多年了,但是使用的并不多,安全管理这个领域,一直是 Shiro 的天下。

相对于 Shiro,在 SSM/SSH 中整合 Spring Security 都是比较麻烦的操作,所以,Spring Security 虽然功能比 Shiro 强大,但是使用反而没有 Shiro 多(Shiro 虽然功能没有 Spring Security 多,但是对于大部分项目而言,Shiro 也够用了)。

自从有了 Spring Boot 之后,Spring Boot 对于 Spring Security 提供了 自动化配置方案,可以零配置使用 Spring Security。

因此,一般来说,常见的安全管理技术栈的组合是这样的:

  • SSM + Shiro
  • Spring Boot/Spring Cloud + Spring Security

注意,这只是一个推荐的组合而已,如果单纯从技术上来说,无论怎么组合,都是可以运行的。

我们来看下具体使用。

项目创建

在 Spring Boot 中使用 Spring Security 非常容易,引入依赖即可:

pom.xml 中的 Spring Security 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

只要加入依赖,项目的所有接口都会被自动保护起来。

体验

我们创建一个 HelloController:

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}

访问 /hello ,需要登录之后才能访问。

当用户从浏览器发送请求访问 /hello 接口时,服务端会返回 302 响应码,让客户端重定向到 /login 页面,用户在 /login 页面登录,登陆成功之后,就会自动跳转到 /hello 接口。

另外,也可以使用 POSTMAN 来发送请求,使用 POSTMAN 发送请求时,可以将用户信息放在请求头中(这样可以避免重定向到登录页面):

通过以上两种不同的登录方式,可以看出,Spring Security 支持两种不同的认证方式:

  • 可以通过 form 表单来认证
  • 可以通过 HttpBasic 来认证

用户名配置

默认情况下,登录的用户名是 user ,密码则是项目启动时随机生成的字符串,可以从启动的控制台日志中看到默认密码:

这个随机生成的密码,每次启动时都会变。对登录的用户名/密码进行配置,有三种不同的方式:

  • 在 application.properties 中进行配置
  • 通过 Java 代码配置在内存中
  • 通过 Java 从数据库中加载

前两种比较简单,第三种代码量略大。

配置文件配置用户名/密码

可以直接在 application.properties 文件中配置用户的基本信息:

spring.security.user.name=javaboy
spring.security.user.password=123

配置完成后,重启项目,就可以使用这里配置的用户名/密码登录了。

Java 配置用户名/密码

也可以在 Java 代码中配置用户名密码,首先需要我们创建一个 Spring Security 的配置类,集成自 WebSecurityConfigurerAdapter 类,如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //下面这两行配置表示在内存中配置了两个用户
        auth.inMemoryAuthentication()
                .withUser("javaboy").roles("admin").password("$2a$10$OR3VSksVAmCzc.7WeaRPR.t0wyCsIj24k0Bne8iKWV1o.V9wsP8Xe")
                .and()
                .withUser("lisi").roles("user").password("$2a$10$p1H8iWa8I4.CA.7Z8bwLjes91ZpY.rYREGHQEInNtAp4NzL6PLKxi");
    }
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
   //不推荐使用下面的过时方法
    @Bean
    PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }
}

这里我们在 configure 方法中配置了两个用户,用户的密码都是加密之后的字符串(明文是 123),从 Spring5 开始,强制要求密码要加密,如果非不想加密,可以使用一个过期的 PasswordEncoder 的实例 NoOpPasswordEncoder,但是不建议这么做,毕竟不安全。

Spring Security 中提供了 BCryptPasswordEncoder 密码编码工具,可以非常方便的实现密码的加密加盐,相同明文加密出来的结果总是不同,这样就不需要用户去额外保存盐的字段了,这一点比 Shiro 要方便很多。

登录配置

对于登录接口,登录成功后的响应,登录失败后的响应,我们都可以在 WebSecurityConfigurerAdapter 的实现类中进行配置。例如下面这样:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    VerifyCodeFilter verifyCodeFilter;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(verifyCodeFilter, UsernamePasswordAuthenticationFilter.class);
        http
        .authorizeRequests()//开启登录配置
        .antMatchers("/hello").hasRole("admin")//表示访问 /hello 这个接口,需要具备 admin 这个角色
        .anyRequest().authenticated()//表示剩余的其他接口,登录之后就能访问
        .and()
        .formLogin()
        //定义登录页面,未登录时,访问一个需要登录之后才能访问的接口,会自动跳转到该页面
        .loginPage("/login_p")
        //登录处理接口
        .loginProcessingUrl("/doLogin")
        //定义登录时,用户名的 key,默认为 username
        .usernameParameter("uname")
        //定义登录时,用户密码的 key,默认为 password
        .passwordParameter("passwd")
        //登录成功的处理器
        .successHandler(new AuthenticationSuccessHandler() {
            @Override
            public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("success");
                    out.flush();
                }
            })
             //登录失败的处理器
            .failureHandler(new AuthenticationFailureHandler() {
                @Override
                public void onAuthenti+cationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException exception) throws IOException, ServletException {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("fail");
                    out.flush();
                }
            })
            .permitAll()//和表单登录相关的接口统统都直接通过
            .and()
            .logout()
            .logoutUrl("/logout")
             //登录注销的处理器
            .logoutSuccessHandler(new LogoutSuccessHandler() {
                @Override
                public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("logout success");
                    out.flush();
                }
            })
            .permitAll()
            .and()
            .httpBasic()
            .and()
            .csrf().disable();
    }
}

我们可以在 successHandler 方法中,配置登录成功的回调,如果是前后端分离开发的话,登录成功后返回 JSON 即可,同理,failureHandler 方法中配置登录失败的回调,logoutSuccessHandler 中则配置注销成功的回调。

有多个 httpSecurity 的时候只需要加上 @Order 这个注解设置优先级就可以了 ( PS:要另外创建一个文件) 多个 httpSecurity 除了优先级用法都是一样的。

springsecurity的权限表达式及说明如下:

表达式 说明
permitAll 永远返回true
denyAll 永远返回false
anonymous 当前用户是anonymous时返回true
rememberMe 当前用户是rememberMe用户时返回true
authenticated 当前用户不是anonymous时返回true
fullAuthenticated 当前用户既不是anonymous也不是rememberMe用户时返回true
hasRole(role) 用户拥有指定的角色权限时返回true
hasAnyRole([role1,role2]) 用户拥有任意一个指定的角色权限时返回true
hasAuthority(authority) 用户拥有指定的权限时返回true
hasAnyAuthority([authority1,authority2]) 用户拥有任意一个指定的权限时返回true
hasIpAddress(’192.168.1.0’) 请求发送的Ip匹配时返回true
SpringSecurity—WebSecurityConfigurerAdapter(自定义配置入口)

忽略拦截

如果某一个请求地址不需要拦截的话,有两种方式实现:

  • 设置该地址匿名访问
  • 直接过滤掉该地址,即该地址不走 Spring Security 过滤器链

推荐使用第二种方案,配置如下:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/vercode");
    }
}

Spring Security 另外一个强大之处就是它可以结合 OAuth2 ,玩出更多的花样出来 。

官方的中文文档:

https://www.springcloud.cc/spring-security-zhcn.html#core-components

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 593871浏览

随机文章
Spring—异步Http
3年前
ElasticSearch—文档路由(八)
5年前
Kotlin-泛型—泛型(二十八)
4年前
ElasticSearch—索引基本操作(五)
5年前
LangChain+RAG—构建知识库(二)
1年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 593871 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付