spring-security入门3---如何自定义登陆页面(二)


项目源码地址 https://github.com/nieandsun/security

1.上篇文章存在的问题

上篇文章虽然完成了自定义登陆页面的目标,但是却存在一些问题:

不符合restful风格
按照restful风格,我的请求localhost:8080/hello是一个rest请求,应该获得一个包含状态的json数据,但是在未登陆时,返回的确是一个html
不适用于前后端分离的项目
比如所我们现在的项目,前端是VUE,登陆页面就写在了前端项目里,前后端交互的方式都是ajax请求,前端获取的数据格式也全是带有状态码的json数据

本篇文章将着力去解决上面提到的问题.

2.配置认证行为

代码如下:

package com.nrsc.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/authentication/require")
                .loginProcessingUrl("/nrsc/signIn")
                .and()
                .authorizeRequests()
                .antMatchers("/authentication/require", "/nrsc-login.html")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .csrf().disable();
    }
}

简单介绍:
在这里插入图片描述

3.在loginPage->即/authentication/require接口中解决上面提到的问题

注意:

  • ResultVO,ResultEnum和ResultVOUtil是我定义的三个用于封装返回结果的类,这里不再过多赘述,大家可以在文首提到的项目源码中获得.
  • 下面的类初步解决了上面提到的两个问题------测试时会进一步去讲
package com.nrsc.security.controller;

import com.nrsc.security.VO.ResultVO;
import com.nrsc.security.enums.ResultEnum;
import com.nrsc.security.utils.ResultVOUtil;
import lombok.extern.slf4j.Slf4j;
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.util.StringUtils;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created By: Sun Chuan
 * Created Date: 2019/6/15 19:55
 */
@RestController
@Slf4j
public class SecurityController {
    //用户在访问我们的项目时,如果需要身份认证,spring-security会根据
    //我在SecurityConfig中loginPage的配置跳转到我自定义的url即/authentication/require,
    //但在这个跳转之前spring-security会将我们的请求缓存到RequestCache的session里,
    //通过该类可以从session中再将缓存的请求信息拿出来
    private RequestCache requestCache = new HttpSessionRequestCache();

    //spring-security提供的类,可以方便的进行重定向
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @RequestMapping("/authentication/require")
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    public ResultVO requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {

        //获取引发跳转的请求
        SavedRequest savedRequest = requestCache.getRequest(request, response);

        //如果有这个引发跳转的请求的话,且该请求以.html结尾,将重定向到我们的登陆页/nrsc-login.html
        if (savedRequest != null) {
            //获取请求的url
            String targetUrl = savedRequest.getRedirectUrl();
            log.info("引发跳转的请求是:" + targetUrl);

            //如果请求url以.html结尾跳转到我们自己写的登录页----在前后端分离的项目里一般不会这样做
            if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
                redirectStrategy.sendRedirect(request, response, "/nrsc-login.html");
            }
        }

        //如果有引发跳转的请求且不以html结尾
        //或者如果没有引发跳转的请求----即直接访问authentication/require
        //返回一个未认证的状态码并引导用户进行登陆
        return ResultVOUtil.error(ResultEnum.UNAUTHORIZED.getCode(), ResultEnum.UNAUTHORIZED.getMessage());
    }
}

4.测试

4.1 发送一个结尾为.html的请求,比如localhost:8080/aa.html

在这里插入图片描述
点击登陆
在这里插入图片描述

4.2 发送rest请求localhost:8080/hello

在这里插入图片描述

5.前后端分离项目用户登陆流程

通过上面的测试我们可以看到,当用户发送rest请求进行认证时,得到的将不再是html而是由我自定义的json数据,对于前后端分离的项目而言,当一个ajax请求得到的json数据中的code为我自定义的800时,就应该引导用户重新进入登陆页进行登陆—>而登陆的URL就是我们上面配置的"/nrsc/signIn", 为此我们可以做如下测试:

5.1先用postman请求localhost:8080/hello

在这里插入图片描述

5.2获得800的code后,再用postman请求localhost:8080/nrsc/signIn即模拟登陆功能

在这里插入图片描述

5.3点击send,完成用户信息认证—>并重新跳转回认证之前的请求

在这里插入图片描述
由4和5可以看到我们已经解决了文章开始时提到的问题.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值