spring security 学习

一、Spring Security简介

Spring Security 是 Spring 家族中的一个安全管理框架,主要用于 Spring 项目组中提供安全认证服务,该框架主要的核心功能有认证、授权和攻击防护。

二、Spring Security入门

(1)Spring Security引入

创建一个最简单的Spring Security工程。引入Spring Web,Spring Securi
创建一个最简单的Spring Security工程。引入Spring Web,Spring Security
创建一个Controller包,并写一个LoginController方法

@Controller
public class LoginController {
   


    @RequestMapping("login")
    public String login(){
   
        System.out.println("执行登录方法");
        return "redirect: main.html";
    }
}

先创建两个html,login.html和main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
<form action="/login" method="post">
    用户名:<input type="text" name="username"/><br/>
    密  码:<input type="password" name="password"/><br/>
    <input type="submit" value="登录"/>
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>main</title>
</head>
<body>
登录成功
</body>
</html>

运行并访问。因为我们还没有修改配置,我们自己写的登录页面还没有起作用。现在我们可以看到Spring Security自带的登录页面。系统默认的username是user。密码会自动在控制台中打印输出。
在这里插入图片描述
在这里插入图片描述

(2)自定义登录

在写登录代码之前我们需要了解Spring Security提供的两个接口。
UserDetailsService
在实际开发中我们不会用Spring Security提供的账号密码,我们都是从数据库中获取的。
我们需要编写一个类来实现UserDetailsService,编写查询数据过程。返回User对象,这个User对象是安全框架自己提供的对象。
PassWordEncoder
对密码加密

创建一个service包,在包下创建一个UserDetailsServiceImpl并实现UserDetailsService

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
   

    @Autowired
    private PasswordEncoder pw;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
   
        //1.查询数据库判断用户是否存在,如果不存在就会抛出usernameNotFoundException异常。我们先自定义一个admin的用户
        if(!"admin".equals(username)){
   
            throw new UsernameNotFoundException("用户名不存在");
        }
        String password=pw.encode("123");
        //返回User对象,这个User对象是安全框架自己提供的对象。
        return new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
    }
}

现在在使用之前的username就会报错
在这里插入图片描述

(3)自定义登录页面

在实际开发往往我们也会自定义登录页面,这样我们实现很精美的登录页面。
我们创建一个config包,再创建一个SecurityConfig类,让它继承WebSecurityConfigurerAdapter。再重写configure(HttpSecurity http)方法。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   


    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        //自定义表单提交
        http.formLogin()
                .loginPage("/login.html");
    }

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

我们再次登录login.html,它会直接来到我们自定义页面。
我们再次登录login.html它会直接来到自定义页面
但是我们尝试登录main.html系统也能登录。所以之前系统自带的认证方法已经失效了。
现在我们就需要自己编写认证。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   


    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        //自定义表单提交
        http.formLogin()
                .loginPage("/login.html");

        //授权认证
        http.authorizeRequests()
                //login.html不需要认证
                .mvcMatchers("/login.html").permitAll()
                //所有请求都必须被认证,这样只有登录后才能访问
                .anyRequest().authenticated();


    }


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

再次运行,我们先使用main.html,发现现在系统会自动跳转登录页面。
但是,我们用之前的username和password是无法登录页面的。
我们需要先关闭csrf防护,同时设置跳转页面,并编写UserDetailsServiceImpl拦截。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   


    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        //自定义表单提交
        http.formLogin()
                //当发现/login时认为时登录,必须和表单提交的地址一样,这样才会去执行UserDetailsServiceImpl
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                
                .successForwardUrl("/main.html");

        //授权认证
        http.authorizeRequests()
                //login.html不需要认证
                .mvcMatchers("/login.html").permitAll()
                //所有请求都必须被认证,这样只有登录后才能访问
                .anyRequest().authenticated();

        //关闭csrf防护
        http.csrf().disable();


    }


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

但是现在会报错。会提示请求方式错误。因为登录成功后跳转页面必须时post请求。
所以我们必须修改跳转方法。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
   


    @Override
    protected void configure(HttpSecurity http) throws Exception {
   
        //自定义表单提交
        http.formLogin()
                //当发现/login时认为时登录,必须和表单提交的地址一样,这样才会去执行UserDetailsServiceImpl
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                //登录成功后跳转页面必须是post请求
                .successForwardUrl("/toMain");

        //授权认证
        http.authorizeRequests()
                //login.html不需要认证
                .mvcMatchers("/login.html").permitAll()
                //所有请求都必须被认证,这样只有登录后才能访问
                .anyRequest().authenticated();

        //关闭csrf防护
        http.csrf().disable();


    }


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

并在LoginController中添加一个toMain方法

  /**
     * 页面跳转
     * @return
     */
    @RequestMapping("toMain")
    public String toMian(){
   
        return "redirect: main.html";
    }

(4)自定义失败页面

我们先创建一个error页面。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Error</title>
</head>
<body>
操作失败,请重新登录<a href="/login.html">跳转</a>
</body>
</html>

在SecurityConfig中编写登录错误时的跳转方法并打开error.html的认证。同时在LoginController中添加一个toError方法

  //自定义表单提交
        http.formLogin()
                //当发现/login时认为时登录,必须和表单提交的地址一样,这样才会去执行UserDetailsServiceImpl
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                //登录成功后跳转页面必须是post请求
                .successForwardUrl("/toMain")
                //跳转失败页面也是post请求
                .failureForwardUrl("/toError");
 //授权认证
        http.authorizeRequests()
                //error.html不需要认证
                .mvcMatchers("/error.html").permitAll()
                //login.html不需要认证
                .mvcMatchers("/login.html").permitAll()
                //所有请求都必须被认证,这样只有登录后才能访问
                .anyRequest().authenticated();

 /**
     * 错误跳转
     * @return
     */
    @RequestMapping("toError")
    public String toError(){
   
        return "redirect: error.html";
    }

(5)自定义登录成功和失败处理器

创建一个handle包,再创建一个MyAuthenticationSuccessHandler类并实现AuthenticationSuccessHandler

public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
   


    private String url;

    public MyAuthenticationSuccessHandler(String url) {
   
        this.url = url;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
   
        response.sendRedirect(url);
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
   
        httpServletResponse.sendRedirect(url);
    }

}

在SecurityConfig中添加successHandler处理器

 //自定义表单提交
        http.formLogin()
                //当发现/login时认为时登录,必须和表单提交的地址一样,这样才会去执行UserDetailsServiceImpl
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                //登录成功后跳转页面必须是post请求
               // .successForwardUrl("/toMain")
                //登录成功后的处理器不能和successForwardUrl共存
                .successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com"))
                //跳转失败页面也是post请求
                .failureForwardUrl("/toError");

与成功处理器相同,我们创建一个MyAuthenticationFHandler类并实现AuthenticationFailureHandler

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
   

    private String url;

    public MyAuthenticationFailureHandler(String url) {
   
        this.url = url;
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
   
        httpServletResponse.sendRedirect(url);
    }
}

在SecurityConfig中添加failureHandler处理器

  //自定义表单提交
        http.formLogin()
                //当发现/login时认为时登录,必须和表单提交的地址一样,这样才会去执行UserDetailsServiceImpl
                .loginProcessingUrl("/login")
                //自定义登录页面
                .loginPage("/login.html")
                //登录成功后跳转页面必须是post请求
               // .successForwardUrl("/toMain")
                //登录成功后的处理器不能和successForwardUrl共存
                .successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com"))
                //跳转失败页面也是post请求
               // .failureForwardUrl("/toError");
               .failureHandler(new MyAuthenticationFailureHandler("/error.html"));

这样可以直接跳转error.html。
在这里插入图片描述

(6)权限判断

我们先创建一个页面main1.html,让拥有admin权限的用户才能看到它。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Main1</title>
</head>
<body>
admin用户才能打开
</body>
</html>

在admin.html中添加一个a标签,跳转main1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>main</title>
</head
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值