• springSecurity自定义用户认证逻辑


    1. 创建项目

    使用idea中的spring 初始化工具引入springbootspringsecruity初始化项目

    最终pom.xml如下

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    	<parent>
    		<groupId>org.springframework.boot</groupId>
    		<artifactId>spring-boot-starter-parent</artifactId>
    		<version>2.2.2.RELEASE</version>
    		<relativePath/> <!-- lookup parent from repository -->
    	</parent>
    	<groupId>com.example</groupId>
    	<artifactId>demo-spring-secruity</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<name>demo-spring-secruity</name>
    	<description>Demo project for Spring Boot</description>
    
    	<properties>
    		<java.version>1.8</java.version>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-security</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-web</artifactId>
    		</dependency>
    		<dependency>
    			<groupId>org.projectlombok</groupId>
    			<artifactId>lombok</artifactId>
    			<version>1.18.10</version>
    		</dependency>
    
    		<dependency>
    			<groupId>org.springframework.boot</groupId>
    			<artifactId>spring-boot-starter-test</artifactId>
    			<scope>test</scope>
    			<exclusions>
    				<exclusion>
    					<groupId>org.junit.vintage</groupId>
    					<artifactId>junit-vintage-engine</artifactId>
    				</exclusion>
    			</exclusions>
    		</dependency>
    		<dependency>
    			<groupId>org.springframework.security</groupId>
    			<artifactId>spring-security-test</artifactId>
    			<scope>test</scope>
    		</dependency>
    	</dependencies>
    
    	<build>
    		<plugins>
    			<plugin>
    				<groupId>org.springframework.boot</groupId>
    				<artifactId>spring-boot-maven-plugin</artifactId>
    			</plugin>
    		</plugins>
    	</build>
    
    </project>
    
    

    创建一个测试控制器

    package com.example.demospringsecruity.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author john
     * @date 2020/1/6 - 9:47
     */
    @RestController
    public class HelloController {
        @GetMapping("/hello")
        public String hello() {
            return "hello spring secruity";
        }
    }
    
    

    运行项目

    访问<http://localhost:8081/hello>,会被跳转到<http://localhost:8081/login>

    输入用户名user和刚才运行项目时输出的密码,登录成功,可以获取到刚才预期的响应

    2. 自定义登录方式

    package com.example.demospringsecruity.config;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    /**
     * @author john
     * @date 2020/1/6 - 10:07
     */
    @Configuration
    public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            // 表单登录
    //        http.formLogin()
            //  基本登录
            http.httpBasic()
                    .and()
                    .authorizeRequests()
                    .anyRequest()
                    .authenticated();
        }
    }
    

    当浏览器发送一个请求后,首先会经过第一个过滤器,UsernamePassowordAuthenticationFilter,这个过滤器中,它会判断你的请求是否带usernamepassword这两个参数,如果带了就进行拦截验证,如果没有就进入到第二个过滤器BasicAuthenticationFilter,这个过滤器会判断请求头中是否含有需要验证的信息,如果没有进入下一个拦截器,最后到ExceptionTranslationFilter拦截器,它会捕获FilterSecurityInterceptor抛出的异常,而FilterSecurityInterceptor会判断这个请求是否校验通过,权限是否通过,以上就是Spring Security框架的一个基本认证流程,FilterSecurityInterceptor是这个框架的最后一个拦截器,所有的请求都必须通过该拦截器的校验。

    3. 自定义用户认证逻辑

    1. 处理用户信息获取逻辑        UserDetailsService
    2. 处理用户校验逻辑	          UserDetails
    3. 处理密码加密解密           PasswordEncoder
    

    UserDetailsService

    用户信息获取逻辑在springsecruity中是被封装在UserDetailService接口中

    package org.springframework.security.core.userdetails;
    
    public interface UserDetailsService {
        UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
    }
    

    UserDetails

    public interface UserDetails extends Serializable {
    	Collection<? extends GrantedAuthority> getAuthorities();//权限的集合
    	String getPassword();//密码
    	String getUsername();//用户名
    	boolean isAccountNonExpired();//账户是否没过期 true-->没过期
    	boolean isAccountNonLocked();//账户是否没锁定 true-->没被锁定
    	boolean isCredentialsNonExpired();//凭证是否没过期 true-->没过期
    	boolean isEnabled();//账户是否可用
    }
    
    

    下面开始编写具体代码
    MyUserDetailsService处理用户信息获取逻辑

    package com.example.demospringsecruity.config;
    
    import lombok.extern.slf4j.Slf4j;
    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;
    
    /**
     * @author john
     * @date 2020/1/6 - 10:32
     */
    @Component
    @Slf4j
    public class MyUserDetailsService implements UserDetailsService {
        //这里可以注入mapper或者repository的dao对象来实现数据校验逻辑操作
        @Autowired
        private PasswordEncoder passwordEncoder;
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            log.info("用户名:" + username);
            //这里密码应该从数据库中取出,暂时先使用加密生成
            String password = passwordEncoder.encode("123456");
            //User类是Spring内置的一个类,实现了UserDetails接口,而这个接口是UserDetailSerice的子接口
            return new User(username,
                    password,
                    true,        // 账户是否可用
                    true,        // 账户是否过期
                    true,        // 密码是否过期
                    true,        //账户是否被锁定
                    AuthorityUtils.commaSeparatedStringToAuthorityList("admin") //授权集合
            );
        }
    }
    

    PasswordConfig处理密码加密解密
    注入PasswordEncoder

    package com.example.demospringsecruity.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @author john
     * @date 2020/1/6 - 12:51
     */
    //说明这个一个配置类,类似spring中的xml文件
    @Configuration
    public class PasswordConfig {
    
        //手动将PasswordEncoder注入到ioc容器中
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
    

    测试在输入用户user密码123456后成功获取数据

    上面的演示我使用了spring-security自己的UserDetails实现类User(org.springframework.security.core.userdetails.User),但实际开发中我们不可能这么用,因为根据实际的业务,往往会希望用户信息表里会包含更多的数据,比如说电话,邮箱,公司职位等信息,那我们该如何去处理呢?

    其实非常简单,我们只要将我们自己的User表继承spring-securityUser类(org.springframework.security.core.userdetails.User),再在MyUserDetailsService里只要返回我们自己的user即可.

  • 相关阅读:
    netcore一键部署到linux服务器以服务方式后台运行
    查找100-999之间的水仙花数
    shell创建数据库的脚本
    python打印九九乘法表的菱形实现
    c++一些重要的细节
    MySQL数据库基础学习笔记(二)
    MySQL数据库基础学习笔记(一)
    react-redux 的基本使用
    react-router-dom基本使用+3种传参方式
    从create-react-app 项目搭建开始
  • 原文地址:https://www.cnblogs.com/ifme/p/12155796.html
Copyright © 2020-2023  润新知