SpringSecurity 认证

SpringSecurity 认证

基本概念

认证

用户认证(Authentication) 是系统认为用户是否能登录

授权

用户授权(Authorization)系统判断用户是否有权限去做某些事情

Web组件

不管是单体结构还是分布式、微服务项目,只要还是Web项目,都会遵循一个主干线:
发起请求>接受请求>处理请求>响应请求

  • filter/interceptor:定位拦截/过滤请求
  • servlet/controller:定位接收请求、处理请求、响应请求
  • listener/applicationListener:监听器
    在这里插入图片描述

案例分析

快速入门

创建 maven 工程 引入依赖

<parent>
    <artifactId>spring-boot-starter-parent</artifactId>
    <groupId>org.springframework.boot</groupId>
    <version>2.3.12.RELEASE</version>
</parent>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>


创建启动类

package com.yy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}


创建controller

package com.yy.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        return  "hello";
    }
}


接口访问

在这里插入图片描述

引入 security

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

访问接口

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

认证

认证定制-用户定制

  • 基于内存
  • 基于数据库
基于内存

@Configuration
public class SpringSecurityConfig {
    @Bean
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("pengyy").password("123456").authorities("p1").build());
        manager.createUser(User.withUsername("xiaoming").password("123456").authorities("p2").build());
        return manager;
    }
    

    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }


}


在这里插入图片描述

认证定制-页面定制

继承WebSecurityConfigurerAdapter,重写configure接口 protected void configure(HttpSecurity http) throws Exception



/**
 * 自定义配置
 */
@Override
protected void configure(HttpSecurity http) throws Exception {
    // 禁用csrf保护
    http.csrf().disable();
    // url 路径权限控制
    http.authorizeRequests()
            // 匹配 /login  /login.html permitAll -- 全部放行
            .antMatchers("/login.html").permitAll()
            .antMatchers("/login").permitAll()
            // anyRequest 匹配所有请求 authenticated 认证拦截
            .anyRequest().authenticated();
    // 用户登录控制
    http.formLogin()
            // 指定登录请求
            .loginProcessingUrl("/login")
            // 指定登录页面
            .loginPage("/login.html");
}


<!-- 在 resources 目录下创建 static 文件夹,在static文件夹下创建 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="password"/><br/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>


认证定制-登录路径定制

loginProcessingUrl(“/user/login”)


/**
 * 自定义配置
 */
@Override
protected void configure(HttpSecurity http) throws Exception {
    // 禁用csrf保护
    http.csrf().disable();
    // url 路径权限控制
    http.authorizeRequests()
            // 匹配 /login  /login.html permitAll -- 全部放行
            .antMatchers("/login.html").permitAll()
            .antMatchers("/user/login").permitAll()
            // anyRequest 匹配所有请求 authenticated 认证拦截
            .anyRequest().authenticated();
    // 用户登录控制
    http.formLogin()
            // 指定登录请求
            .loginProcessingUrl("/user/login")
            // 指定登录页面
            .loginPage("/login.html");
}


认证定制-登录参数定制

usernameParameter(“uname”)
passwordParameter(“passwd”)


/**
 * 自定义配置
 */
@Override
protected void configure(HttpSecurity http) throws Exception {
    // 禁用csrf保护
    http.csrf().disable();
    // url 路径权限控制
    http.authorizeRequests()
            // 匹配 /login  /login.html permitAll -- 全部放行
            .antMatchers("/login.html").permitAll()
            .antMatchers("/user/login").permitAll()
            // anyRequest 匹配所有请求 authenticated 认证拦截
            .anyRequest().authenticated();
    // 用户登录控制
    http.formLogin()
            // 指定登录请求
            .loginProcessingUrl("/user/login")
            // 指定登录页面
            .loginPage("/login.html")
            .usernameParameter("uname")
            .passwordParameter("passwd");
}


认证定制-登录成功跳转路径定制

SpringSecurity登录成功后,默认跳转到上一个路径,如果需要定制跳转路径,可以使用下面配置
successForwardUrl(“/success”)


// 用户登录控制
http.formLogin()
    // 指定登录请求
    .loginProcessingUrl("/user/login")
    // 指定登录页面
    .loginPage("/login.html")
    .usernameParameter("uname")
    .passwordParameter("passwd")
    .successForwardUrl("/success");


认证定制-登录失败跳转路径定制

failureForwardUrl(“/fail”) 登录失败,定制的跳转路径需要放通
antMatchers(“/fail”).permitAll()


/**
 * 自定义配置
 */
@Override
protected void configure(HttpSecurity http) throws Exception {
    // 禁用csrf保护
    http.csrf().disable();
    // url 路径权限控制
    http.authorizeRequests()
            // 匹配 /login  /login.html permitAll -- 全部放行
            .antMatchers("/login.html").permitAll()
            .antMatchers("/user/login").permitAll()
            .antMatchers("/fail").permitAll()
            // anyRequest 匹配所有请求 authenticated 认证拦截
            .anyRequest().authenticated();
    // 用户登录控制
    http.formLogin()
            // 指定登录请求
            .loginProcessingUrl("/user/login")
            // 指定登录页面
            .loginPage("/login.html")
            .usernameParameter("uname")
            .passwordParameter("passwd")
            .successForwardUrl("/success")
            .failureForwardUrl("/fail");
}


认证定制-登录成功逻辑定制

successHandler(new MyAuthenticationSuccessHandler())

// 登录成功之后处理器
.successHandler(new MyAuthenticationSuccessHandler())
// 登录成功跳转
.successForwardUrl(“/success”)

如果登陆成功之后处理器和登陆成功跳转两个都设置了,那么往后的会覆盖前面的,以上 successHandler 登录成功处理器在 successForwardUrl 登录成功跳转的上面,那么最终是以 successForwardUrl 为主


package com.yy.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * 登录成功之后处理器
 */
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        // 自定义登录成功之后逻辑
        // 传统项目
        // response.sendRedirect("/success");
        // 前后端分离项目--json
        response.setContentType("application/json;charset=utf-8");
        String data = "{\"code\":200,\"msg\": \"登录成功\",\"data\": null}";
        response.getWriter().write(data);
    }
}


// 用户登录控制
http.formLogin()
    // 指定登录请求
    .loginProcessingUrl("/user/login")
    // 指定登录页面
    .loginPage("/login.html")
    // 修改登录用户名、密码参数
    .usernameParameter("uname")
    .passwordParameter("passwd")
    //  登录成功之后处理器
    .successHandler(new MyAuthenticationSuccessHandler())
    //  登录成功跳转
    .successForwardUrl("/success")
    // 登录失败跳转
    .failureForwardUrl("/fail");


认证定制-登录失败逻辑定制

failureHandler(new MyAuthenticationFailureHandler())


package com.yy.handler;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        // 自定义登录失败之后逻辑
        // 传统项目
        // response.sendRedirect("/success");
        // 前后端分离项目--json
        response.setContentType("application/json;charset=utf-8");
        String data = "{\"code\":200,\"msg\": \"登录失败\",\"data\": "+exception.getMessage()+"}";
        response.getWriter().write(data);
    }
}


// 用户登录控制
http.formLogin()
   // 指定登录请求
   .loginProcessingUrl("/user/login")
   // 指定登录页面
   .loginPage("/login.html")
   // 修改登录用户名、密码参数
   .usernameParameter("uname")
   .passwordParameter("passwd")
   // 登录成功跳转
   // .successForwardUrl("/success")
   // 登录成功之后处理器
   .successHandler(new MyAuthenticationSuccessHandler())
   // 登录失败跳转
   // .failureForwardUrl("/fail")
   // 登录失败之后处理器
   .failureHandler(new MyAuthenticationFailureHandler());


认证定制-登出控制

默认 /logout ,定制的话使用
http.logout()
.logoutUrl(“/user/logout”);

认证定制-登出成功跳转路径定制

logoutSuccessUrl(“/logout-success”) 登出成功跳转路径需要放开
antMatchers(“/logout-success”).permitAll()


/**
 * 自定义配置
 */
@Override
protected void configure(HttpSecurity http) throws Exception {
    // 禁用csrf保护
    http.csrf().disable();
    // url 路径权限控制
    http.authorizeRequests()
            // 匹配 /login  /login.html permitAll -- 全部放行
            .antMatchers("/login.html").permitAll()
            .antMatchers("/user/login").permitAll()
            .antMatchers("/fail").permitAll()
            .antMatchers("/logout-success").permitAll()
            // anyRequest 匹配所有请求 authenticated 认证拦截
            .anyRequest().authenticated();
    // 用户登录控制
    http.formLogin()
            // 指定登录请求
            .loginProcessingUrl("/user/login")
            // 指定登录页面
            .loginPage("/login.html")
            // 修改登录用户名、密码参数
            .usernameParameter("uname")
            .passwordParameter("passwd")
            // 登录成功跳转
            // .successForwardUrl("/success")
            // 登录成功之后处理器
            .successHandler(new MyAuthenticationSuccessHandler())
            // 登录失败跳转
            // .failureForwardUrl("/fail")
            // 登录失败之后处理器
            .failureHandler(new MyAuthenticationFailureHandler());
    http.logout()
            .logoutUrl("/user/logout")
            .logoutSuccessUrl("/logout-success");
}


认证定制-登出成功逻辑定制

logoutSuccessHandler(new MyLogoutSuccessHandler());


package com.yy.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request,
                                HttpServletResponse response,
                                Authentication authentication) throws IOException, ServletException {
        // 自定义登出成功之后逻辑
        // 传统项目
        // response.sendRedirect("/success");
        // 前后端分离项目--json
        response.setContentType("application/json;charset=utf-8");
        String data = "{\"code\":200,\"msg\": \"登出成功\",\"data\": null}";
        response.getWriter().write(data);
    }
}



http.logout()
    .logoutUrl("/user/logout")
    // .logoutSuccessUrl("/logout-success")
    .logoutSuccessHandler(new MyLogoutSuccessHandler());


认证完整代码


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
    用户名:<input type="text" name="uname"/><br/>
    密码:<input type="password" name="passwd"/><br/>
    <input type="submit" value="提交"/>
</form>
</body>
</html>



package com.yy.config;
import com.yy.handler.MyAuthenticationFailureHandler;
import com.yy.handler.MyAuthenticationSuccessHandler;
import com.yy.handler.MyLogoutSuccessHandler;
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.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("pengyy").password("123456").authorities("p1").build());
        manager.createUser(User.withUsername("xiaoming").password("123456").authorities("p2").build());
        return manager;
    }
    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }
    /**
     * 自定义配置
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 禁用csrf保护
        http.csrf().disable();
        // url 路径权限控制
        http.authorizeRequests()
                // 匹配 /login  /login.html permitAll -- 全部放行
                .antMatchers("/login.html").permitAll()
                .antMatchers("/user/login").permitAll()
                .antMatchers("/fail").permitAll()
                .antMatchers("/logout-success").permitAll()
                // anyRequest 匹配所有请求 authenticated 认证拦截
                .anyRequest().authenticated();
        // 用户登录控制
        http.formLogin()
                // 指定登录请求
                .loginProcessingUrl("/user/login")
                // 指定登录页面
                .loginPage("/login.html")
                // 修改登录用户名、密码参数
                .usernameParameter("uname")
                .passwordParameter("passwd")
                // 登录成功跳转
                // .successForwardUrl("/success")
                // 登录成功之后处理器
                .successHandler(new MyAuthenticationSuccessHandler())
                // 登录失败跳转
                // .failureForwardUrl("/fail")
                // 登录失败之后处理器
                .failureHandler(new MyAuthenticationFailureHandler());
        http.logout()
                .logoutUrl("/user/logout")
                // .logoutSuccessUrl("/logout-success")
                .logoutSuccessHandler(new MyLogoutSuccessHandler());
    }
}


package com.yy.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello";
    }
    @RequestMapping("/success")
    public String success(){
        return "success";
    }
    @RequestMapping("/fail")
    public String fail(){
        return "fail";
    }
    @RequestMapping("/logout-success")
    public String logoutSuccess(){
        return "logout-success";
    }
}



package com.yy.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
 * 登录成功之后处理器
 */
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        // 自定义登录成功之后逻辑
        // 传统项目
        // response.sendRedirect("/success");
        // 前后端分离项目--json
        response.setContentType("application/json;charset=utf-8");
        String data = "{\"code\":200,\"msg\": \"登录成功\",\"data\": null}";
        response.getWriter().write(data);
    }
}



package com.yy.handler;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        // 自定义登录失败之后逻辑
        // 传统项目
        // response.sendRedirect("/success");
        // 前后端分离项目--json
        response.setContentType("application/json;charset=utf-8");
        String data = "{\"code\":200,\"msg\": \"登录失败\",\"data\": "+exception.getMessage()+"}";
        response.getWriter().write(data);
    }
}


package com.yy.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request,
                                HttpServletResponse response,
                                Authentication authentication) throws IOException, ServletException {
        // 自定义登出成功之后逻辑
        // 传统项目
        // response.sendRedirect("/success");
        // 前后端分离项目--json
        response.setContentType("application/json;charset=utf-8");
        String data = "{\"code\":200,\"msg\": \"登出成功\",\"data\": null}";
        response.getWriter().write(data);
    }
}


  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值