Spring Security(三)

Spring Security(三)

个性化用户认证流程

自定义登录页面

在配置类中指定登录页面和接收登录的 url

@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 启用表单登陆
        http.formLogin()
                // 指定登录页面
                .loginPage("/imooc-signIn.html")
                // 登录页面表单提交的 action
                .loginProcessingUrl("/authentication/form")
                .and()
                // 对请求做授权
                .authorizeRequests()
                // 访问指定url时不需要身份认证(放行)
                .antMatchers("/imooc-signIn.html").permitAll()
                // 任何请求
                .anyRequest()
                // 都需要身份认证
                .authenticated()
                .and()
                .csrf().disable();
    }
}
  • 在项目中新建登录页面
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <h2>标准登录页面</h2>
    <h3>表单登录</h3>
    <form action="/authentication/form" method="post">
        <table>
            <tr>
                <td>用户名:</td>
                <td><label>
                    <input type="text" name="username" />
                </label></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><label>
                    <input type="password" name="password" />
                </label>
                </td>
            </tr>
            <tr>
                <td colspan="2">
                    <button type="submit">登录</button>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

启动项目时再访问 Security 就会跳转到你自已定义的登陆页面让你登录。

  • 深入定义(判断是PC端还是移动端,PC端跳转页面,移动端响应 json)

创建一个控制器,用来处理操作

@RestController
public class BrowserSecurityController {

    private static final Logger log = LoggerFactory.getLogger(BrowserSecurityController.class);

    private RequestCache requestCache = new HttpSessionRequestCache();

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    /**
     * 当需要身份验证时跳转到这里处理
     */
    @RequestMapping("/authentication/require")
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    public Map<String, String> requireAuthentication(final HttpServletRequest request,
                                                final HttpServletResponse response) throws IOException {
        SavedRequest savedRequest = requestCache.getRequest(request, response);
        if (null != savedRequest) {
            String target = savedRequest.getRedirectUrl();
            log.info("引发跳转的请求是 ={}", target);
            if (StringUtils.endsWithIgnoreCase(target, ".html")) {
                redirectStrategy.sendRedirect(request, response, "/imooc-signIn.html");
            }
        }
        Map<String, String> map = new HashMap<>();
        map.put("status", "401");
        map.put("msg", "error");
        map.put("content","访问的服务需要身份认证,请引导用户到登录页!" );
        return map;
    }
}
自定义登录成功处理

要做自定义登录成功处理需要实现一下 Security 的 AuthenticationSuccessHandler 接口

/**
 * 自定义登录成功处理
 */
@Configuration
public class ImoocAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
    private static final Logger log = LoggerFactory.getLogger(ImoocAuthenticationSuccessHandler.class);

    private final ObjectMapper objectMapper;

    @Autowired
    public ImoocAuthenticationSuccessHandler(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }
    // 参数 Authentication 是Security的核心接口之一,封装了用户登录认证信息
    // UserDetails 接口就包装到了此接口中
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        log.info("登录成功");
        // 响应 json 信息
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write(objectMapper.writeValueAsString(authentication));
        out.flush();
        out.close();
    }

}
  • 启动项目,访问跳转登录页面后,输入正确用户名,密码后响应信息如下:
{
  "authorities": [
    {
      "authority": "admin"
    }
  ],
  // 包含了认证请求的信息
  "details": {
    "remoteAddress": "127.0.0.1",
    "sessionId": "1126C43793FD600CA6DC74169A38F64E"
  },
  // 这里代表当前用户是否经过了身份认证,boolean表示
  "authenticated": true,
  // 这里是 我们自定义UserDetailsService接口实现类 返回的数据
  "principal": {
    "password": null,
    "username": "user",
    // 用户权限
    "authorities": [
      {
        "authority": "admin"
      }
    ],
    "accountNonExpired": true,
    "accountNonLocked": true,
    "credentialsNonExpired": true,
    "enabled": true
  },
  // 这里一般代表用户输入的密码,Security 做了处理,前台不会响应
  "credentials": null,
  // 用户名
  "name": "user"
}
自定义登录错误处理

要做自定义登录成功处理需要实现一下 Security 的 AuthenticationFailureHandler 接口

/**
 * 自定义登录失败处理
 */
@Configuration
public class ImoocAuthenticationFailureHandler implements AuthenticationFailureHandler {
    // 参数 AuthenticationException 是 Security 的一个抽象异常类
    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {

    }

}
  • 启动项目,访问跳转登录页面后,输入错误用户名,密码后响应信息如下:
{**省略堆栈信息**"localizedMessage":"坏的凭证","message":"坏的凭证","suppressed":[]}

注意:以上两个自定义登录/失败的处理,一定要在 自定义Security配置类中加入,不然不会生效!!!

加入自定义登录成功/失败处理

/**
 * Security 配置
 */
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecurityProperties securityProperties;

    @Autowired
    private ImoocAuthenticationSuccessHandler imoocAuthenticationSuccessHandler;

    @Autowired
    private ImoocAuthenticationFailureHandler imoocAuthenticationFailureHandler;

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        BrowserProperties browser = securityProperties.getBrowser();
        // 启用表单登陆
        http.formLogin()
                // 指定登录页面
                .loginPage("/authentication/require")
                // 登录页面表单提交的 action
                .loginProcessingUrl("/authentication/form")
                // 引入自己定义的登录成功处理配置类
                .successHandler(imoocAuthenticationSuccessHandler)
                // 引入自己定义的登录失败处理配置类
                .failureHandler(imoocAuthenticationFailureHandler)
                .and()
                // 对请求做授权
                .authorizeRequests()
                // 访问指定url时不需要身份认证(放行)
                .antMatchers("/authentication/require",
                        browser.getLoginPage()).permitAll()
                // 任何请求
                .anyRequest()
                // 都需要身份认证
                .authenticated()
                .and()
                .csrf().disable();

    }
}

以上实现了自定义成功/失败响应,但是要想PC/移动端通用,需要深化配置一下

  • 改造 自定义成功处理

创建一个枚举类,用来区分 重定向,还是响应 json

public enum LoginType {

    REDIRECT, JSON;

}

让此枚举类成为 BrowserProperties 类的一个属性

public class BrowserProperties {

    /**
     * 指定默认值(如果配置了用配置的页面,没配置用默认的。)
     */
    private String loginPage = "/imooc-signIn.html";

    /**
     * 指定登录成功/失败后的响应方式
     */
    private LoginType loginType = LoginType.JSON;

    // 省略 GET/SET/toString 方法
}

改造自定义成功处理类

/**
 * 自定义登录成功处理
 */
@Configuration
// 让自定义的成功处理类 继承 Security 默认的成功处理类 SavedRequestAwareAuthenticationSuccessHandler
public class ImoocAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {

    private static final Logger log = LoggerFactory.getLogger(ImoocAuthenticationSuccessHandler.class);

    private final ObjectMapper objectMapper;

    private final SecurityProperties securityProperties;

    @Autowired
    public ImoocAuthenticationSuccessHandler(ObjectMapper om, SecurityProperties sp) {
        this.objectMapper = om;
        this.securityProperties = sp;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication) throws IOException, ServletException {
        log.info("登录成功。。。");
        // 响应 json 信息
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.write(objectMapper.writeValueAsString(authentication));
        out.flush();
        out.close();
    }

}

改造自定义失败处理类

/**
 * 自定义登录失败处理
 */
@Configuration
// SimpleUrlAuthenticationFailureHandler 为 Security 默认的登录失败处理类
public class ImoocAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {

    private static final Logger log = LoggerFactory.getLogger(ImoocAuthenticationSuccessHandler.class);

    private final ObjectMapper objectMapper;

    private final SecurityProperties securityProperties;

    @Autowired
    public ImoocAuthenticationFailureHandler(ObjectMapper om, SecurityProperties sp) {
        this.objectMapper = om;
        this.securityProperties = sp;
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request,
                                        HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        log.info("登录失败。。。");
        // 如果配置了用 Json 响应
        if (LoginType.JSON.equals(securityProperties.getBrowser().getLoginType())) {
            // 响应状态码为 500
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            // 响应 json 信息
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write(objectMapper.writeValueAsString(exception));
            out.flush();
            out.close();
        } else {
            // 调用父类方法
            super.onAuthenticationFailure(request, response, exception);
        }
    }
}

由于 BrowserProperties 类中的loginType属性默认为 Json ,你可以在具体的 properties 文件中,定义一下属性。如:

imooc.security.browser.login-type=REDIRECT

这样可以测试一下是否配置成功。

测试图就不贴上了,自已耐心测试一下~ :-)

原文地址:https://www.cnblogs.com/yliucnblogs/p/10274928.html

时间: 2024-11-09 21:58:12

Spring Security(三)的相关文章

Spring Security应用开发(19)基于方法的授权(三)AOP

本文介绍使用AOP的配置方式来实现基于方法的授权. (1)首先使用Spring Security提供的protect-pointcut进行配置. protect-pointcut结点配置访问符合指定条件的方法锁需要的角色列表. <!-- 使用AOP的方式来定义方法级别的访问控制 --> <sec:global-method-security> <sec:protect-pointcut access="ROLE_USER,ROLE_ADMIN" expre

Spring Security 3 (三) 用户数据存放于数据库

上章回顾: 上一章中,我们将用户名.密码以及用户对应的角色都配置于applicationContext-security.xml中,基本实现了我们能控制用户的访问权限.但是在现实开发中,我们不可能将用户信息硬编码在配置文件中,通常我们都是存放到数据中.同时我们应该对用户的密码进行加密存储. 目标: 1.将用户信息存放于数据库 2.对用户的密码进行加密 详细操作: 1.其他代码参考上一章中代码.本章中,首先我们要创建一张数据表来记录我们的用户信息.SpringSecurity提供的验证机制中,首先

Spring Security教程(三):自定义表结构

在上一篇博客中讲解了用Spring Security自带的默认数据库存储用户和权限的数据,但是Spring Security默认提供的表结构太过简单了,其实就算默认提供的表结构很复杂,也不一定能满足项目对用户信息和权限信息管理的要求.那么接下来就讲解如何自定义数据库实现对用户信息和权限信息的管理. 一.自定义表结构 这里还是用的mysql数据库,所以pom.xml文件都不用修改.这里只要新建三张表即可,user表.role表.user_role表.其中user用户表,role角色表为保存用户权限

Spring Security 动态url权限控制(三)

一.前言 本篇文章将讲述Spring Security 动态分配url权限,未登录权限控制,登录过后根据登录用户角色授予访问url权限 基本环境 spring-boot 2.1.8 mybatis-plus 2.2.0 mysql 数据库 maven项目 Spring Security入门学习可参考之前文章: SpringBoot集成Spring Security入门体验(一)https://blog.csdn.net/qq_38225558/article/details/101754743

Spring Security 入门(三)

在说完了Spring Security框架的功能和执行流程后,就到了写它Spring Boot的集成,先来看最简的配置: <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> </parent>

Spring Security(三十一):9.6 Localization(本地化)

Spring Security supports localization of exception messages that end users are likely to see. If your application is designed for English-speaking users, you don't need to do anything as by default all Security messages are in English. If you need to

Spring Security(三十四):10.4 Jackson Support

Spring Security has added Jackson Support for persisting Spring Security related classes. This can improve the performance of serializing Spring Security related classes when working with distributed sessions (i.e. session replication, Spring Session

Spring Security入门Demo

一.spring Security简介 SpringSecurity,这是一种基于Spring AOP和Servlet过滤器的安全框架.它提供全面的安全性解决方案,同时在Web请求级和方法调用级处理身份确认和授权.在Spring Framework基础上,Spring Security充分利用了依赖注入(DI,Dependency Injection)和面向切面技术. 二.建立工程 参考http://blog.csdn.net/haishu_zheng/article/details/51490

CAS 与 Spring Security 3整合配置详解

一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分.用户认证指的是验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统.用户授权指的是验证某个用户是否有权限执行某个操作.在一个系统中,不同用户所具有的权限是不同的.比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改.一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限. 对于上面提到的两种应用情景,Spring Security 框