Spring Security OAuth2.0 认证协议【2】hello world(基于 SpringBoot)

上一篇:https://blog.csdn.net/LawssssCat/article/details/105065992

下一篇:https://lawsssscat.blog.csdn.net/article/details/105080690

Hello World

SpringBoot集成Spring Security入门体验

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
@RestController
public class IndexController {
    @GetMapping("/index")
    public String index() {
        return "Hello World ~";
    }
}

运行项目访问 http://127.0.0.1:8080/index

温馨小提示:在不进行任何配置的情况下,Spring Security 给出的默认用户名为 user 密码则是项目在启动运行时随机生成的一串字符串,会打印在控制台,如下图:

认证成功之后才会跳转到我们的index页面

配置用户密码

有很多方式,静态写死、从数据库中取、rest方式从第三方接口中取…

下面讲两种静态写死的方法

  1. 直接写在application.yml里
spring:
  security:
    user:
      name: admin  # 用户名
      password: 123456 # 密码

或者

  1. 新建Security <mark>核心</mark> 配置类继承 WebSecurityConfigurerAdapter (建议)
package com.example.securitydemo.config;

import org.apache.tomcat.util.security.MD5Encoder;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.MessageDigestPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/** * @author alan smith * @version 1.0 * @date 2020/3/24 15:36 */
@Configuration
// 启动 spring security 的 web 安全支持
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /** * 将用户设置在内存中 * * @param auth * @throws Exception */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 获取加密者
        PasswordEncoder passwordEncoder = passwordEncoder();

        // 在内存中写入用户信息
        auth.inMemoryAuthentication()
                // 指定加密方式
                .passwordEncoder(passwordEncoder)
                .withUser("admin").password(passwordEncoder.encode("123456")).roles("ADMIN")
                .and()
                .withUser("test").password(passwordEncoder.encode("111111")).roles("USER");
    }

    private PasswordEncoder passwordEncoder() {
        // return new MessageDigestPasswordEncoder("MD5")
        // or
        // BCryptPasswordEncoder: Spring Security 提供的加密工具,可快速实现加密加盐
        return new BCryptPasswordEncoder();
    }
}

admin/123456 访问并登录 localhost:8080/index (成功)

注意:因为没有指定默认的登录成功后转跳的地址,那么默认是 /
也是说,如果你 访问的是 localhost:8080/login
那么,登录成功后会转跳到 localhost:8080/ 地址(而这个地址我们没有定义,因此就报错了)

  1. 从数据库中获取用户账号、密码信息
    这种方式也就是我们项目中通常使用的方式,这个留到 <mark>后面的文章再说</mark>

登录处理 与 忽略拦截

package com.example.securitydemo.controller;

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/** * @author alan smith * @version 1.0 * @date 2020/3/24 15:28 */
@RestController
public class IndexController {

    @GetMapping("/index")
    public String index() {
        return "hello world";
    }

    @GetMapping("/home")
    public String home() {
        return "home";
    }

    @GetMapping("/getUserInfo")
    public Object userInfo() {
        return SecurityContextHolder.getContext();
    }
}

重点!

修改 Security <mark>核心</mark> 类 ,重写 三个 configure 方法

package com.example.securitydemo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.io.PrintWriter;

/** * {@link WebSecurityConfigurerAdapter}: * spring security 提供的 {@link WebSecurity} 适配器 * 一个帮我们实现了大部分{@link WebSecurityConfigurer}接口的抽象类 * <p> * 提供了可以重写的configure方法,在方法内可以装配自定义的Filter配置 * 其指定的Filter会被生产为{@link FilterChainProxy} * 最终以{@link DelegatingFilterProxy}作为spring Security Filter Chain起作用 * <p> * 即:其实现是用来配置spring Security Filter Chain的 * * @author alan smith * @version 1.0 * @date 2020/3/24 15:36 */
@Configuration
// 启动 spring security 的 web 安全支持
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /** * 将用户设置在内存中 * * @param auth 封装认证授权管理器 * @throws Exception */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 获取加密者
        PasswordEncoder passwordEncoder = passwordEncoder();

        // 在内存中写入用户信息
        auth.inMemoryAuthentication()
                // 指定加密方式
                .passwordEncoder(passwordEncoder)
                // 录入 admin 用户信息,自定义 ADMIN 权限
                .withUser("admin").password(passwordEncoder.encode("123456")).roles("ADMIN")
                .and()
                // 录入 test 用户信息,自定义 USER 权限
                .withUser("test").password(passwordEncoder.encode("111111")).roles("USER");
    }

    private PasswordEncoder passwordEncoder() {
        // return new MessageDigestPasswordEncoder("MD5")
        // or
        // BCryptPasswordEncoder: Spring Security 提供的加密工具,可快速实现加密加盐
        return new BCryptPasswordEncoder();
    }

    /** * 对Filter的配置 * * @param web 对web请求的封装,可以操作Filter * @throws Exception */
    @Override
    public void configure(WebSecurity web) throws Exception {
        // 设置拦截忽略 url - 会直接过滤改url - 将不会经过 Spring Security 过滤器链
        web
                // 设置拦截忽略文件夹,请求 url 匹配则不拦截
                .ignoring().antMatchers("/favicon.ico")
                .and()
                // 可以对静态资源放行
                .ignoring().antMatchers("/css/**", "/js/**");
    }

    /** * 对FilterChain的配置 * * @param http 对http请求和响应的封装,可以操作FilterChain * @throws Exception */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 开启登录匹配
        http.authorizeRequests()
                // 标识访问 '/index' 这个接口,需要具备 ADMIN 角色
                .antMatchers("/index").hasRole("ADMIN")
                // 设置可匿名匿名访问的标识
                .antMatchers("/", "/home").permitAll()
                // 其余所有请求都需要认证
                .anyRequest().authenticated()

                .and()

                // 设置登录认证页面
                .formLogin()
                // 配置(自定义的)登录页面的 url
                //.loginPage("/login")
                // 自定义登录用户名和密码的属性名,默认为 username 和 password
                .usernameParameter("username1")
                .passwordParameter("password1")
                // 登录后的(默认)转跳 - 方式1
                .loginProcessingUrl("/home")
                // 登录后的(默认)转跳 - 方式2
                .successHandler((req, resp, authentication) -> {
                    //resp.sendRedirect("/home");
                    System.out.println(SecurityContextHolder.getContext());
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("登录成功...");
                    out.flush();
                })
                // 配置登录失败的回调 - 方式1
                //.failureForwardUrl("/home")
                // 配置登录失败的回调 - 方式2
                .failureHandler((req, resp, exception) -> {
                    resp.setContentType("application/json;carset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("登录失败...");
                    out.flush();
                })
                // 和表单登录相关的接口统统都自接通过
                .permitAll()

                .and()

                .logout()
                .logoutUrl("/logout")
                // 配置注销成功的回调
                .logoutSuccessHandler((req, resp, authentication) -> {
                    resp.setContentType("application/json;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.write("注销成功...");
                    out.flush();
                })
                .permitAll()

                .and()
                // 开启 http basic 认证
                .httpBasic()
                .and()
                // 关闭 csrf 跨域
                .csrf().disable();


    }
}

未登录

http://localhost:8080/home (无需登陆)

下面两个,都会转跳到 /login 页面
http://localhost:8080/getUserInfo (需登陆)
http://localhost:8080/index (ADMIN 权限)

admin/123456 登陆后

admin 登陆后
http://localhost:8080/index (ADMIN 权限)

http://localhost:8080/getUserInfo (需登陆)

http://localhost:8080/logout (登出)

test/111111 登陆

http://localhost:8080/login

http://localhost:8080/getUserInfo (需登陆)

http://localhost:8080/index (ADMIN 权限)
【失败:因为当前账号不是 ADMIN 权限】

done

Github 下载


归档

# 参考

# 核心配置图

Spring Security 文章被收录于专栏

Spring Security、OAuth2.0、JWT

全部评论

相关推荐

05-12 17:00
门头沟学院 Java
king122:你的项目描述至少要分点呀,要实习的话,你的描述可以使用什么技术,实现了什么难点,达成了哪些数字指标,这个数字指标尽量是真实的,这样面试应该会多很多,就这样自己包装一下,包装不好可以找我,我有几个大厂最近做过的实习项目也可以包装一下
点赞 评论 收藏
分享
家人们,我现在真的好纠结。我是26届的,目前还没有实习过。我现在的情况是,想参加秋招,但是感觉自己的简历特别空,没有实习经历会不会秋招直接凉凉啊?可我又听说现在很多公司对26届实习生也不太感冒,说什么不确定性大。而且我最近在准备考公,时间上也有点冲突。要是把时间花在实习上,备考时间就少了。但要是不实习,又怕以后就业有问题😫有没有懂行的友友帮我分析分析:26届现在不实习,秋招找工作真的会很难吗?考公和实习该怎么平衡啊?如果现在不实习,考完公再去找实习还来得及吗?真的太焦虑了,希望大家能给我点建议🙏
小破站_程序员YT:我可能和大家的观点不一样。人的精力是有限的,不能既要还要。你又想实习又想考公最后又要秋招上岸,我觉得哪有那么多的选择。你如果想考上岸,那就全力以赴。如果想秋招上岸,就继续投实习,投没了,就继续准备秋招,秋招不行继续春招。别到最后,考公没上岸,觉得是花了时间浪费在找实习上了, 秋招没上岸,觉得是浪费时间准备考公去了。我是认为很难说可以去平衡 不喜勿喷,可以叫我删除
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务