【Spring Security OAuth2】- spring security - 个性化用户认证流程1

作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析


阶段4、深入jdk其余源码解析


阶段5、深入jvm源码解析

码哥源码部分

码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】

码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】

码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】

​​​​​​码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】

码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】

码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】

码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】

终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!

打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】

个性化用户认证流程1

前面使用spring security默认的认证流程。处理了自定义的用户数据,密码加密;
但是在实际开发中,肯定是要使用自己开发的页面、登录成功失败的业务处理等。

本节内容
* 自定义登录页
* 自定义登录成功处理
* 自定义登录失败处理

自定义登录页面

在cn.mrcode.imooc.springsecurity.securitybrowser.BrowserSecurityConfig中修改配置

    
            http
                    // 定义表单登录 - 身份认证的方式
                    .formLogin()
                    .loginPage("/imocc-signIn.html")
                    .and()
                    .authorizeRequests()
                    // 放行这个路径
                    .antMatchers("/imocc-signIn.html").permitAll()

如果不对该静态文件放行的话,将会无限跳转,造成错误:localhost 将您重定向的次数过多。

对于html存放资源文件夹下的哪一个目录,这个有点懵逼:

最后放在static下面才能访问到

    |- resources
      |-static
       |-imocc-signIn.html

html内容如下

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>标准登录页面</title>
    </head>
    <body>
    <h2>标准登录页面</h2>
    <h3>表单登录</h3>
    <form action="/authentication/form" method="post">
        | 用户名:||
| :-----: | :-----: | 
| 用户名: |  | 
| 密码: |  | 
| 登录 | 

    </form>
    </body>
    </html>

注意这里的路径:acrion="/authentication/form";路径是自定义的,
而UsernamePasswordAuthenticationFilter默认是处理/login路径的登录请求

    public UsernamePasswordAuthenticationFilter() {
      super(new AntPathRequestMatcher("/login", "POST"));
    }
    .formLogin()
    .loginPage("/imocc-signIn.html")
    // 处理登录请求路径
    .loginProcessingUrl("/authentication/form")
    .and()
    .authorizeRequests()
    .antMatchers("/imocc-signIn.html").permitAll()

我的天,以后一定要注意看方法名好吗?英文不好就是这么容易被看懵逼。不知道怎么弄

再次测试,没有出现和视频中一样的出现_csrf的错误情况,而是又跳回来登录页面了;

但是把scrf关闭之后,就正常了;最后这个完整的配置如下

    http
            .formLogin()
            .loginPage("/imocc-signIn.html")
            .loginProcessingUrl("/authentication/form")
            .and()
            .authorizeRequests()
            .antMatchers("/imocc-signIn.html").permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .csrf().disable();  // csrf 在后面章节会讲解

这里有一个疑问的问题:

loginProcessingUrl("/authentication/form") 会认为必须是跳转到我们自己写的这个真是存在的控制器里面,
实际上这个路径对应的控制器不存在也没有关系。因为不会走。
这里看起来更像是对security默认/login路径的重命名;

这里虽然配置了自定义的路径,但是都统一跳转到了静态页面,
那么要怎么实现 根据请求来分发是返回html内容?还是返回json内容呢?
在前后分离的情况下,都用ajax来请求,肯定不能返回html咯;

处理不同类型的请求

202306181907186201.png

思路是上面图中这样。那么很简单只要把登录地址换成自定义的就好了。

    @Configuration
    public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        // 有三个configure的方法,这里使用http参数的
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
    
                    .formLogin()
    //                .loginPage("/imocc-signIn.html")
                    // 更换成自定义的一个真实存在的处理器地址
                    .loginPage("/authentication/require")
                    .loginProcessingUrl("/authentication/form")
                    .and()
                    .authorizeRequests()
                    // 放行这个路径
                    .antMatchers("/imocc-signIn.html", "/authentication/require").permitAll()
                    .anyRequest()
                    .authenticated()
                    .and()
                    .csrf().disable()
            ;
        }
    }

编写处理请求的处理器

    package cn.mrcode.imooc.springsecurity.securitybrowser;
    
    import cn.mrcode.imooc.springsecurity.securitybrowser.support.SimpleResponse;
    import org.apache.catalina.servlet4preview.http.HttpServletRequest;
    import org.apache.commons.lang3.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.security.web.DefaultRedirectStrategy;
    import org.springframework.security.web.RedirectStrategy;
    import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
    import org.springframework.security.web.savedrequest.RequestCache;
    import org.springframework.security.web.savedrequest.SavedRequest;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseStatus;
    import org.springframework.web.bind.annotation.RestController;
    
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * ${desc}
     * @author zhuqiang
     * @version 1.0.1 2023/8/3 14:58
     * @date 2023/8/3 14:58
     * @since 1.0
     */
    @RestController
    public class BrowserSecurityController {
        Logger logger = LoggerFactory.getLogger(getClass());
        // 封装了引发跳转请求的工具类,看实现类应该是从session中获取的
        private RequestCache requestCache = new HttpSessionRequestCache();
    
        // spring的工具类:封装了所有跳转行为策略类
        private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    
        /**
         * 当需要身份认证时跳转到这里
         * @param request
         * @param response
         * @return
         */
        @RequestMapping("/authentication/require")
        @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
        public SimpleResponse requirAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
    
            SavedRequest savedRequest = requestCache.getRequest(request, response);
            // 如果有引发认证的请求
            // spring 在跳转前应该会把信息存放在某个地方?
            if (savedRequest != null) {
                String targetUrl = savedRequest.getRedirectUrl();
                logger.info("引发跳转的请求:" + targetUrl);
                // 如果是html请求,则跳转到登录页
                if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
                    redirectStrategy.sendRedirect(request, response, "/imocc-signIn.html");
                }
            }
            // 否则都返回需要认证的json串
            return new SimpleResponse("访问的服务需要身份认证,请引导用户到登录页");
        }
    }

SimpleResponse 类只是一个返回结果的信息类

    package cn.mrcode.imooc.springsecurity.securitybrowser.support;
    
    public class SimpleResponse {
        private Object content;
    
        public SimpleResponse(Object content) {
            this.content = content;
        }
    
        public Object getContent() {
            return content;
        }
    
        public void setContent(Object content) {
            this.content = content;
        }
    }

我们的目的是写一个可重用的安全模块,需要把一些配置(比如这里的html静态页面的配置)让使用方来配置

思路是使用配置文件:

在security-demo/application.yml中;

注意: 这里我才看明白视频中被依赖的security-browser项目没有写启动类,也没有自己的application.yml配置文件;
应该就是只写一个可重用的模块

    imooc:
      security:
        browser:
          loginPage: /demo-signIn.html

该模块大概会提供20多项配置,所以封装成配置类,分为不同的功能,结构如下:

    - SecurityProperties 项目提供的配置类
    - BrowserProperties
    - ValidateCodeProperties
    - Oath2Properties
    - SocialProperties

core 配置类的编写

由于这些配置类是 app 和 browser 项目公用的,写在core里面

    package cn.mrcode.imooc.springsecurity.securitycore.properties;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    /**
     * ${desc}
     * @author zhuqiang
     * @version 1.0.1 2023/8/3 15:28
     * @date 2023/8/3 15:28
     * @since 1.0
     */
    @ConfigurationProperties(prefix = "imooc.security")
    public class SecurityProperties {
        /** imooc.security.browser 路径下的配置会被映射到该配置类中 */
        private BrowserProperties browser = new BrowserProperties();
    
        public BrowserProperties getBrowser() {
            return browser;
        }
    
        public void setBrowser(BrowserProperties browser) {
            this.browser = browser;
        }
    }
    
    
    package cn.mrcode.imooc.springsecurity.securitycore.properties;
    
    public class BrowserProperties {
        /** 登录页面路径 */
        private String loginPage = "/imocc-signIn.html";
    
    
        public String getLoginPage() {
            return loginPage;
        }
    
        public void setLoginPage(String loginPage) {
            this.loginPage = loginPage;
        }
    }

为了职责分离,单独写一个入口被扫描开启的配置类

    package cn.mrcode.imooc.springsecurity.securitycore;
    
    import cn.mrcode.imooc.springsecurity.securitycore.properties.SecurityProperties;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * 让SecurityProperties这个配置类生效
     * EnableConfigurationProperties 的作用是标明加载哪一个类
     * 这效果和直接在目标类上写上@Configuration效果一样
     */
    @Configuration
    @EnableConfigurationProperties(SecurityProperties.class)
    public class SecurityCoreConfig {
    }

使用配置类重构brower

之前写死 登录页面 相关代码处都需要更改从配置类中获取,使用 Autowired 注解可以获得SecurityProperties配置类实例

    @Autowired
    private SecurityProperties securityProperties;
    
    
    // 别忘记了拦截放行的地方也需要更改为配置类的属性
    .antMatchers("/authentication/require",
                securityProperties.getBrowser().getLoginPage()).permitAll()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值