2021/09/13笔记

我们于2021/09/13 的学习目标是:SpringSecurity,核心任务为:

1、学习技术:

1)、SpringSecurity简介

2)、SpringSecurity快速入门

3)、UserDetailsService

4)、BCryptPasswordEncoder

5)、自定义登录

6)、认证过程其他常用配置

2、文档总结

1)、SpringSecurity简介

SpringSecurity是是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。

它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了 Spring IoC , DI(控制反转Inversion ofControl,DI:Dependency Injection 依赖注入) 和 AOP(面向切面编程) 功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

2)、SpringSecurity快速入门

pom.xml导入依赖

<!--Spring Security依赖-->

    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-web</artifactId>

    </dependency>



    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-security</artifactId>

    </dependency>



    <dependency>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-test</artifactId>

    </dependency>

  </dependencies>

使用浏览器访问http://localhost:8080/,自动跳转到默认登录页面

 

导入spring-boot-starter-security启动器后,Spring Security 已经生效,默认拦截全部请求,如果用户没有登录,跳转到登录页面。

默认的username为user,password打印在控制台中。注意每次运行生成的密码都不一致。

Using generated security password: e04ca9f5-f389-4982-b114-81d6488e0d59

3)、UserDetailsService

当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。所以我们要通过自定义逻辑控制认证逻辑。如果需要自定义逻辑时,只需要实现 UserDetailsService 接口即可。

package org.example.service.imp;



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.Service;



import javax.annotation.Resource;



@Service

public class UserDetailsServiceImpl implements UserDetailsService {

    @Resource

    private PasswordEncoder encoder;





    @Override

    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        if(!(s.equals("sdf")))

            throw new UsernameNotFoundException("用户记录不存在!!");

        String password = encoder.encode("345");

        return new User(s,password, AuthorityUtils

            .commaSeparatedStringToAuthorityList

                    ("normal,ROLE_abc,/admin.html"));

    }

}

4)、BCryptPasswordEncoder

BCryptPasswordEncoder 是 Spring Security 官方推荐的密码解析器,是对 bcrypt 强散列方法的具体实现。是基于Hash算法实现的单向加密。可以通过strength控制加密强度,默认 10。

encode():给密码编码

@Test
public void encode() {

        System.out.println(new BCryptPasswordEncoder().encode("myPwD!234567"));

        //$2a$10$v5zc4C/OWNry0gb1rZanq.GCqv/2AS.kfzYc.aUfc8sB.vyCABKyW

        //每次编码生成的字符都不相同

}

matches():验证输入的密码与进行编码后的原始密码是否相符

@Test
public void decode(){

    System.out.println(new BCryptPasswordEncoder().matches("myPwD!234567","$2a$10$v5zc4C/OWNry0gb1rZanq.GCqv/2AS.kfzYc.aUfc8sB.vyCABKyW"));

    //true
}

upgradeEncoding():如果解析的密码能够再次进行解析且达到更安全的结果则返回true,否则返回 false。默认返回 false

@Test
public void encodeUpgrade() {

    System.out.println(new BCryptPasswordEncoder().upgradeEncoding("$2a$10$v5zc4C/OWNry0gb1rZanq.GCqv/2AS.kfzYc.aUfc8sB.vyCABKyW"));

    //false
}

5)、自定义登录

自定义login.html登录页面

<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <title>Title</title>

</head>

<body>

<form action="/login" method="post">

    用户名:<input type="text" name="userName" /><br/>

    密码:<input type="password" name="userPwd" /><br/>

    <input type="submit" value="登录" />

</form>

</body>

</html>

 

编写SecurityConfig配置类

package org.example.config;



import org.example.handler.LoginFailHandler;

import org.example.handler.LoginSuccessHandler;

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;



import javax.annotation.Resource;



/**

 * 自定义登录配置

 */

@Configuration

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource

    private LoginSuccessHandler successHandler;

    @Resource

    private LoginFailHandler loginFailHandler;



    @Override

    protected void configure(HttpSecurity http) throws Exception {

        //禁用csrf

        http.csrf().disable();

        //配置自定义登录表单页面信息

        http.formLogin()

                .loginPage("/login.html")

                .loginProcessingUrl("/login")

                .successForwardUrl("/toMain")

                .failureForwardUrl("/toError")

                .usernameParameter("userName")

                .passwordParameter("userPwd");

        //资源放行

        http.authorizeRequests()

                .antMatchers("/login.html")

                    .permitAll()

                .anyRequest()

                    .authenticated();

    }



    @Bean

    public PasswordEncoder passwordEncoder(){

        return new BCryptPasswordEncoder();

    }



    public String passwordEncoder(String password) {

        return new BCryptPasswordEncoder().encode(password);

    }

}

自定义UserDetailServiceImp逻辑类

package org.example.service.imp;



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.Service;



import javax.annotation.Resource;



@Service

public class UserDetailsServiceImpl implements UserDetailsService {

    @Resource

    private PasswordEncoder encoder;





    @Override

    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {

        if(!(s.equals("admin")))

            throw new UsernameNotFoundException("用户记录不存在!!");

        String password = encoder.encode("123456");

        return new User(s,password, AuthorityUtils

            .commaSeparatedStringToAuthorityList

                    ("normal,ROLE_abc,/admin.html"));

    }

}

编写MainController控制器类

package org.example.controller;



import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;



@Controller

public class MainController {

    @RequestMapping("toMain")

    public String toMain(){

        return "redirect:main.html";

    }



    public String toError(){

        return "redirect:error.html";

    }

}

6)、认证过程其他常用配置

编写页面error.html

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Title</title>

</head>

<body>

操作失败,请重新登录 <a href= "/login.html">跳转</a>

</body>

</html>

 

修改控制器的方法

/**

* 失败后跳转页面

* @return

*/

@RequestMapping("/toError")

public String toError(){

   return "redirect:/error.html";

}

配置器放行错误页面

//资源放行
        http.authorizeRequests()

                .antMatchers("/login.html","/error.html")//放行登录页面和错误页面

                    .permitAll()

                .anyRequest()

                    .authenticated();

自定义登录成功处理器

使用successForwardUrl()时表示成功后转发请求到地址。内部是通过 successHandler() 方法进行控制成功后交给哪个类进行处理

//FormLoginConfigurer类文件

package org.springframework.security.config.annotation.web.configurers;

import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.web.authentication.ForwardAuthenticationFailureHandler;
import org.springframework.security.web.authentication.ForwardAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractAuthenticationFilterConfigurer<H, FormLoginConfigurer<H>, UsernamePasswordAuthenticationFilter> {
    public FormLoginConfigurer() {
        super(new UsernamePasswordAuthenticationFilter(), (String)null);
        this.usernameParameter("username");
        this.passwordParameter("password");
    }

    public FormLoginConfigurer<H> loginPage(String loginPage) {
        return (FormLoginConfigurer)super.loginPage(loginPage);
    }

    public FormLoginConfigurer<H> usernameParameter(String usernameParameter) {
        ((UsernamePasswordAuthenticationFilter)this.getAuthenticationFilter()).setUsernameParameter(usernameParameter);
        return this;
    }

    public FormLoginConfigurer<H> passwordParameter(String passwordParameter) {
        ((UsernamePasswordAuthenticationFilter)this.getAuthenticationFilter()).setPasswordParameter(passwordParameter);
        return this;
    }

    public FormLoginConfigurer<H> failureForwardUrl(String forwardUrl) {
        this.failureHandler(new ForwardAuthenticationFailureHandler(forwardUrl));
        return this;
    }

    public FormLoginConfigurer<H> successForwardUrl(String forwardUrl) {
        this.successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
        return this;
    }

    public void init(H http) throws Exception {
        super.init(http);
        this.initDefaultLoginFilter(http);
    }

    protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
        return new AntPathRequestMatcher(loginProcessingUrl, "POST");
    }

    private String getUsernameParameter() {
        return ((UsernamePasswordAuthenticationFilter)this.getAuthenticationFilter()).getUsernameParameter();
    }

    private String getPasswordParameter() {
        return ((UsernamePasswordAuthenticationFilter)this.getAuthenticationFilter()).getPasswordParameter();
    }

    private void initDefaultLoginFilter(H http) {
        DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = (DefaultLoginPageGeneratingFilter)http.getSharedObject(DefaultLoginPageGeneratingFilter.class);
        if (loginPageGeneratingFilter != null && !this.isCustomLoginPage()) {
            loginPageGeneratingFilter.setFormLoginEnabled(true);
            loginPageGeneratingFilter.setUsernameParameter(this.getUsernameParameter());
            loginPageGeneratingFilter.setPasswordParameter(this.getPasswordParameter());
            loginPageGeneratingFilter.setLoginPageUrl(this.getLoginPage());
            loginPageGeneratingFilter.setFailureUrl(this.getFailureUrl());
            loginPageGeneratingFilter.setAuthenticationUrl(this.getLoginProcessingUrl());
        }

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值