JAVA语言之spring-security 个性化用户认证流程——自定义登录页面(可配置)
小标 2019-02-28 来源 : 阅读 1085 评论 0

摘要:本文主要向大家介绍了JAVA语言之spring-security 个性化用户认证流程——自定义登录页面(可配置),通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了JAVA语言之spring-security 个性化用户认证流程——自定义登录页面(可配置),通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

JAVA语言之spring-security 个性化用户认证流程——自定义登录页面(可配置)

1.定义自己的登录页面
我们需要根据自己的业务系统构建自己的登录页面以及登录成功、失败处理
在spring security提供给我的登录页面中,只有用户名、密码框,而自带的登录成功页面是空白页面(可以重定向之前请求的路径中),而登录失败时也只是提示用户被锁定、过期等信息。



在实际的开发中,则需要更精细力度的登录控制,记录错误的日志(错误的次数等)



2.自定义登录页面



  • 配置登录页面的路径
    BrowserSecurityConfig类中配置登录页面的路径

        http.formLogin()  
        .loginPage("/sign.html")   //位于resources/resources/sign.html
        .and()
        .authorizeRequests()
        .anyRequest().authenticated();


    页面内容如下:


    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>sign.html</title>
    </head>
    <body>
    <h2>标准登录页面</h2>
    <h3>表单登录</h3>
    <form action="/authentication/form" method="post">
        <table>
            <tr>
                <td>用户名:</td> 
                <td><input type="text" name="username"></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type="password" name="password"></td>
            </tr>
            <tr>
                <td colspan="2"><button type="submit">登录</button></td>
            </tr>
        </table>
    </form>
    </body>
    </html>


启动之后,访问我们的路径://localhost:8080/sign.html

这个时候浏览器会报错:重定向的次数过多,这是为什么呢?
因为在配置中,我们只是配置了loginPage("/sign.html"),但是又没有给该请求做授权,又因为没有做授权,又被跳转给sign.html页面,所以会是:重定向的次数过多。
此时:需要再配置授权路径,改造之后


        http.formLogin()  
        .loginPage("/sign.html")  
        .and()
        .authorizeRequests()
        .antMatchers("/sign.html").permitAll()  //当访问sign.html这个页面的时候不需要进行身份认证
        .anyRequest().authenticated();


在sign.html中,自己配置了一个post路径,在spring security原理中,表单登录实际上是由UsernamePasswordAuthenticationFilter这个过滤器来处理的,在这个过滤器中

处理的是/login 请求,为了让UsernamePasswordAuthenticationFilter这个过滤器知道处理我们自定义的登录路径/authentication/form,还需要再配置登录的处理请求


        http.formLogin()  
        .loginPage("/sign.html")  
        .loginProcessingUrl("/authentication/form") //登录请求
        .and()
        .authorizeRequests()
        .antMatchers("/sign.html").permitAll() 
        .anyRequest().authenticated();


启动之后,继续访问我们的路径://localhost:8080/sign.html

输入账户名和密码,登录之后会报错,403


在默认情况下,spring security提供了跨站请求伪造的防护,用CSRF Token来完成的,在***和防护的时候再细讲,目前先把跨站请求伪造的功能先disable掉。


        http.formLogin()  
        .loginPage("/sign.html")  
        .loginProcessingUrl("/authentication/form") //登录请求
        .and()
        .authorizeRequests()
        .antMatchers("/sign.html").permitAll() 
        .anyRequest().authenticated()
        .and()
        .csrf().disable();


启动之后,继续访问我们的路径://localhost:8080/user/1 ,系统会帮我们重定向到sign.html页面
此时我们输入正确的用户名和密码就可以访问我们的请求了

3.优化rest请求和html请求
完成了基本功能之后还需要继续优化我们的代码结构,是要面向可重用的一种。
目前有2个问题:



  • 发送的请求,例如:localhost:8080/user/1 需要身份认证的话返回HTML是不合理的,rest服务应该返回json
    想要做到的效果,如果是html请求则返回登录页上,如果不是则返回json数据 带未授权(401状态码)


  • 我们写了一个标准的登录页面,但是我们的目标是提供可重用的安全模块,这个时候就需要提供可配置项
    (因为会有多个项目使用该模块,但是多个项目它有不同的登录模块)
    流程如下:



当我们接收到html请求或者数据请求的时候,先判断是否需要身份认证(spring security来做的)如果是否的话就直接返回了,如果是的话则需要跳转到我们自定义的Controller上面去(目前我们的做法是跳转到了sign.html页面上)在该方法内判断是html请求还是数据请求。


Controller


@RestController
public class BrowserSecurityController {
    private Logger logger = LoggerFactory.getLogger(BrowserSecurityConfig.class);

    //拿到引发跳转的请求(HttpSessionRequestCache把当前的请求缓存到Session中)
    private RequestCache requestCache = new HttpSessionRequestCache();

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Autowired
    private SecurityProperties securityProperties;

    //当需要身份认证时,跳转到这里
    @RequestMapping("/authentication/require")
    @ResponseStatus(code=HttpStatus.UNAUTHORIZED) //不是html请求时,返回401状态码
    public SimpleResponse requireAuthentication(HttpServletRequest request,HttpServletResponse response) throws IOException {
        //之前缓存的请求(可以拿到引发跳转的请求)
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        if (savedRequest != null) {
            String targetUrl = savedRequest.getRedirectUrl();
            logger.info("引发跳转的请求是:"+targetUrl);
            //是否以.html结尾,如果是则跳转到登录页面
            if (StringUtils.endsWithIgnoreCase(targetUrl, ".html")) {
                //这个url,我们需要做成可配置的url(因为我们不可能每次都跳转到我们自己的写的固定登录页面,需要根据每个项目的不同)
                //这个时候就需要用到**Properties 配置文件类来做灵活性配置
                redirectStrategy.sendRedirect(request, response, securityProperties.getBrowser().getLoginPage());
            }
            //如果不是html请求,则返回401状态码以及错误信息
        }
        return new SimpleResponse("访问的服务需要身份认证,请引导用户到登录页");
    }
}


SecurityProperties自定义的登录页配置属性类,为了可配置化


#另外的项目的登录请求的页面
core.security.browser.loginPage = /demo-sign.html


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>demo-sign</title>
</head>
<body>
    <h2>demo-sign自定义登录页</h2>
</body>
</html>


而我们不想单纯的要一个简单的配置是,而是可管理的配置类,因为后面会有其他的配置,例如验证码的配置,OAuth的配置,等 这个时候需要同一个的配置类入口(SecurityProperties


//读取配置文件内的信息
@ConfigurationProperties(prefix="core.security")
public class SecurityProperties {
    private BrowserProperties browser = new BrowserProperties();

    public BrowserProperties getBrowser() {
        return browser;
    }
    public void setBrowser(BrowserProperties browser) {
        this.browser = browser;
    }
}

public class BrowserProperties {
    //标准的登录页面,如果其他项目没有配置则使用默认的登录配置
    private String loginPage = "/sign.html";

    public String getLoginPage() {
        return loginPage;
    }
    public void setLoginPage(String loginPage) {
        this.loginPage = loginPage;
    }
}

//为了使core.security生效则需要一个@Configuration类
@Configuration
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityCoreConfig {
}

//最后要在权限配置类**BrowserSecurityConfig**中 配置放行的url
  private final static String loginPage = "/authentication/require";
    @Autowired
    private SecurityProperties securityProperties;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()  
        .loginPage(loginPage)
        .loginProcessingUrl("/authentication/form")
        .and()
        .authorizeRequests()
        .antMatchers(loginPage).permitAll()
        //自定义的登录页面权限放开
        .antMatchers(securityProperties.getBrowser().getLoginPage()).permitAll()
        .anyRequest().authenticated()
        .and()
        .csrf().disable();
    }


第一种情况:访问请求://localhost:8080/user/1

第二种情况:访问请求://localhost:8080/index.html

第三种情况:关闭配置,继续访问请求://localhost:8080/index.html


#core.security.browser.loginPage = /demo-sign.html


这个功能就是我们目前想要的,可以针对不同的请求对于没有权限时的拦截以及调整判断。

   

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程