Spring boot 的认证与授权 Spring Security 5.3 使用数据库帐号进行验证登录,并获取登录帐号的信息

步骤:

  1. 创建表 admins。
  2. 新建一个实体类AdminEntity,实现接口:org.springframework.security.core.userdetails.UserDetails(包含自定义的字段)。
  3. 创建对应于表 admins 的Mapper接口:AdminMapper。
  4. 创建AdminService接口并实现接口:org.springframework.security.core.userdetails.UserDetailsService。
  5. 创建类AdminServiceImpl并实现AdminService接口。主要是实现方法:loadUserByUsername
  6. 创建配置类,实现接口:org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
  7. 创建配置类,实现接口:org.springframework.security.authentication.AuthenticationProvider(登录验证逻辑)
  8. 获取登录帐号的信息

开始:

1.建表:

CREATE TABLE `grp_admins` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `insert_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` int(4) NOT NULL DEFAULT '0' COMMENT '账号是否注销',
  `user_name` varchar(50) NOT NULL COMMENT '用户账号',
  `pwd` varchar(255) NOT NULL COMMENT '密码',
  `memo` varchar(255) NOT NULL DEFAULT '' COMMENT '备注',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `user_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COMMENT='管理员账户表';

2.创建实体类:实现接口org.springframework.security.core.userdetails.UserDetails

package com.xxx.entity;

import java.sql.Timestamp;
import java.util.Collection;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;


@Data
public class AdminEntity implements UserDetails{

    private Long id;
    private Timestamp insertTime;
    private Timestamp updateTime;
    private Integer isDeleted;
    private String userName;
    private String pwd;
    private String memo;

    @Override
    public Collection<GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return pwd;
    }

    @Override
    public String getUsername() {
        return userName;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

}

3.创建AdminMapper:

package com.xxx.mapper;

import com.wansecheng.entity.AdminEntity;
import java.util.List;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;


@Mapper
public interface AdminMapper {
    
    @Select("SELECT * FROM grp_admins WHERE id=#{id}")
    public AdminEntity getById(Long id);
    
    @Select("SELECT * FROM grp_admins WHERE is_deleted=0 AND user_name=#{username}")
    public AdminEntity getByUserName(String username);
    
    @Select("<script>SELECT * FROM grp_admins WHERE is_deleted=0<if test=\"username!=null and username!=''\"> AND user_name LIKE '%${username}%'</if></script>")
    public List<AdminEntity> search(String username);
    
    @Options(useGeneratedKeys = true, keyColumn = "id")
    @Insert("INSERT INTO grp_admins (user_name, pwd, memo) VALUES (#{userName}, #{pwd}, #{memo})")
    public Integer insert(AdminEntity admin);
    
    @Update("UPDATE grp_admins SET memo=#{memo} WHERE id=#{id}")
    public Integer update(AdminEntity admin);
    
    @Update("UPDATE grp_admins SET is_deleted=1 WHERE id=#{id}")
    public Integer deleteById(Long id);
}

4.创建Service接口:AdminService

package com.xxx.service;

import com.wansecheng.entity.AdminEntity;
import java.util.List;
import org.springframework.security.core.userdetails.UserDetailsService;


public interface AdminService extends UserDetailsService{
    public AdminEntity getById(Long id);
    public AdminEntity getLoginAdminByUsername(String username);
    public List<AdminEntity> search(String username);
    public Long save(AdminEntity admin);
    public Integer removeById(Long id);
}

5.创建类AdminServiceImpl实现AdminService接口(主要是实现与登录验证有关的方法loadUserByUsername

package com.xxx.service.impl;

import com.wansecheng.entity.AdminEntity;
import com.wansecheng.mapper.AdminMapper;
import com.wansecheng.service.AdminService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class AdminServiceImpl implements AdminService {
    
    @Autowired
    private AdminMapper adminMapper;

    @Override
    public AdminEntity getById(Long id) {
        return adminMapper.getById(id);
    }

    @Override
    public AdminEntity getLoginAdminByUsername(String username) {
        return adminMapper.getByUserName(username);
    }

    @Override
    public List<AdminEntity> search(String username) {
        return adminMapper.search(username);
    }

    @Override
    public Long save(AdminEntity admin) {
        if(admin.getId() == null){
            BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            admin.setPwd(passwordEncoder.encode(admin.getPwd()));
            
            adminMapper.insert(admin);
        }else{
            adminMapper.update(admin);
        }
        return admin.getId();
    }

    @Override
    public Integer removeById(Long id) {
        return adminMapper.deleteById(id);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return adminMapper.getByUserName(username);
    }

}

6.创建配置类,实现接口:org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter

package com.xxx.config;

import com.wansecheng.service.impl.AdminServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class AdminWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    AdminServiceImpl adminServiceImpl;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/admin/**").authenticated() // 限制/admin下的页面必须登录后才可访问
                
                .antMatchers("/**").permitAll() // 非 /admin下的页面可以访问
                
                .and()
                .formLogin() // 表示使用自定义登录表单
                .loginPage("/admin/login") // 自定义登录页面(使用controller),页面上的表单要post到/admin/loginPage
                .usernameParameter("uname").passwordParameter("pwd") // 自定义登录表单输入框名称
                .defaultSuccessUrl("/admin/dashboard") // 登录成功后的默认页
                .permitAll() // 登录页允许没登录的情况访问
                
                .and()
                .rememberMe() // 表示在登录表单中使用记住我功能
                .rememberMeParameter("remember") // 表单记住我的checkbox元素的name
                .userDetailsService(adminServiceImpl) // 记住我功能要用到,需要用到UserDetailsService
                
                .and()
                .logout() // 表示使用自定义登出表单
                .logoutUrl("/admin/logout") // 自定义登出页面(使用controller),页面上的表单要POST到/admin/logoutPage
                .logoutSuccessUrl("/admin/login?logout") // 登出后跳转到的页面
                .permitAll() // 登出页允许没登录的情况访问

                .and().headers().frameOptions().disable() // 允许iframe中发送的请求

                .and().csrf().disable(); // 先禁用掉csrf,否则POST的时候会报403
        super.configure(http); //To change body of generated methods, choose Tools | Templates.
    }

}

7.创建配置类,实现接口:org.springframework.security.authentication.AuthenticationProvider

package com.xxx.config;

import com.wansecheng.service.impl.AdminServiceImpl;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Component;


@Component
public class AdminAuthenticationProvider implements AuthenticationProvider {
    
    @Autowired
    private AdminServiceImpl adminServiceImpl;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        
        String username = authentication.getName(); // 获取提交的帐号
        String password = authentication.getCredentials().toString(); // 获取提交的密码

        /*
        String usernameDb = "uss"; // 帐号(模拟从数据库中取出来)
        String passwordDb = "$2a$10$nt24iQDnTy0OFgM3i5cS2ufghcP1/T/ygn8NWxfLzMzkFn9bsMoVW"; // 密码是:abc

        boolean isPassword = BCrypt.checkpw(password, passwordDb); // 比较密码是否一致
*/
        UserDetails admin = adminServiceImpl.loadUserByUsername(username);
        
        //boolean isPassword = password.equals(admin.getPwd());
        boolean isPassword = BCrypt.checkpw(password, admin.getPassword());
        
        if (admin != null && isPassword) {
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password, new ArrayList()); // 创建认证的token
            token.setDetails(admin);  // 将登录帐号的信息放入token,以便Controller可以获取相关信息
            
            // 登录成功返回
            return token;
        } else {
            // 帐号或密码校验失败
            throw new BadCredentialsException("username or password invalid.");
        }
    }

    @Override
    public boolean supports(Class<?> type) {
        return true;
    }

}

8.获取登录帐号的信息:

package com.xxx.controller;

import com.wansecheng.entity.AdminEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;

public class IndexController {
    
    @GetMapping("/test")
    public String index(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        AdminEntity admin = (AdminEntity)authentication.getDetails();
        return admin.getId().toString(); // 这里获取到了登录帐号的ID
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值