(七)、SpringBoot + SpringSecurity 简单登录认证

可以前往第一篇博客查看目录结构 --> 这里

一、查看是否依赖Spring Security相关jar包(例如: spring-boot-starter-security) ,修改demo模块下的 application.propertiies(打开spring security认证)

//注释掉这段配置,开启springsecurity
#security.basic.enabled=false

二、编写简单的html登录页面,放在browser模块下的 src -> main -> resources -> resources -> zeke-login.html

(表单提交地址是:/authentication/form   待会需要用到)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Login Page</title>
</head>
<body>
<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>

三、在browser模块 src->main->java->com->zeke->browser新建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;
    }
}

四、在browser模块 src->main->java->com->zeke->browser新建authentication目录,创建认证失败和认证成功的处理类(ZekeAuthenticationSuccessHandler,ZekeAuthenticationFailureHandler)

只上代码不解释,自行参悟 (有基础的应该都能懂)

ZekeAuthenticationSuccessHandler : 

@Component
public class ZekeAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Autowired
    private SecurityProperties securityProperties;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
        logger.info("登录成功");

        if (LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())){
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(MAPPER.writeValueAsString(authentication));
        }else {
            super.onAuthenticationSuccess(request, response, authentication);
        }

    }
}

ZekeAuthenticationFailureHandler : 

@Component
public class ZekeAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler{

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final ObjectMapper MAPPER = new ObjectMapper();

    @Autowired
    private SecurityProperties securityProperties;

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        logger.info("登录失败");

        if (LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())){
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(MAPPER.writeValueAsString(new SimpleResponse(exception.getMessage())));
        }else {
            super.onAuthenticationFailure(request, response, exception);
        }

    }
}


五、编写SpringSecurity配置类 -> BrowserSecurityConfig

@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private ZekeAuthenticationSuccessHandler zekeAuthenticationSuccessHandler;

    @Autowired
    private ZekeAuthenticationFailureHandler zekeAuthenticationFailureHandler;

    @Autowired
    private SecurityProperties securityProperties;

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
        http.formLogin() //表单登录
                .loginPage("/authentication/require") //用户未登录时的处理地址
                .loginProcessingUrl("/authentication/form") //用户登录
                .successHandler(zekeAuthenticationSuccessHandler) //登录成功处理
                .failureHandler(zekeAuthenticationFailureHandler) //登录失败处理
                .and()
                .authorizeRequests()
                .antMatchers("/authentication/require",
                        securityProperties.getBrowser().getLoginPage()) //不拦截的URL
                .permitAll()
                .anyRequest()
                .authenticated();
    }
}

六、实现UserDetailsService用户操作接口

package com.zeke.browser;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
public class MyUserDetailsService implements UserDetailsService {

    private Logger logger = LoggerFactory.getLogger(getClass());
    //一定要在配置文件中手动注入这个接口的实现类,否则会启动失败或登录失败
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        logger.info("login username: " + username);

        String encode = passwordEncoder.encode("123456");

        logger.info("login password: " + encode);

        return new User(username,encode,
                true,true,true,true,
                AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }

}

七、登录请求处理类 BrowserSecurityController (未登录状态下只有敲带有.html后缀的地址才能直接进入登录页面,否则自行定义需要跳转的页面)

@RestController
public class BrowserSecurityController {

    private Logger logger = LoggerFactory.getLogger(getClass());
    private RequestCache requestCache = new HttpSessionRequestCache();
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Autowired private SecurityProperties securityProperties;

    /**
     * 登录页面请求
     * @param request
     * @param response
     * @return
     * @throws IOException
     */
    @RequestMapping("/authentication/require")
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    public SimpleResponse requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        if (savedRequest != null){
            String redirectUrl = savedRequest.getRedirectUrl();
            logger.info("引发跳转的请求是:" + redirectUrl);
            if (StringUtils.endsWithIgnoreCase(redirectUrl,".html")){
                redirectStrategy.sendRedirect(request,response,securityProperties.getBrowser().getLoginPage());
            }
        }
        return new SimpleResponse("访问的服务器需要身份认证,请引导用户验证登录页");
    }

}

八、启动项目 访问 localhost/zeke-login.html , 输入任意用户名和密码123456(已在代码中定义),查看日志登录成功即可

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值