spring-security + spring-boot + mybatisPlus用户权限访问控制

spring-security + spring-boot + mybatisPlus用户权限访问控制

1)基础原理

Spring-Security本质是一个过滤器链,有很多的过滤器
通过查看源码

FilterSecurityIntercepter //这是一个方法级的权限过滤器,基本位于过滤链的最底部
ExceptionTranslationFilter    //这是个异常过滤器,用来处理再认证授权时过程中抛出的异常
UsernamePasswordAuthenticationFilter  //这是一个对/login的POST请求做拦截,校验表单中的用户名和密码等功能

两个重要的接口:

UserDetailsService接口 :查询数据库和用户名和密码过程

1、创建类继承UsernamePasswordAuthenticationFilter,重写里的三个方法
2、创建类实现UserDetailService,编写查询数据过程,返回User对象,这个User对象是安全框架提供的对象

PasswordEncoder接口:数据加密接口,用于返回User对象里面的密码加密

1)web权限方案

设置登录的用户名和密码:第一种方式:通过配置文件。第二种方式:通过配置类。第三种方式:自定义编写实现类

1、配置appication.properties文件设置登录的用户名和密码

在这里插入图片描述

2、通过配置类配置用户名和密码
spring.security.user.name=admin
spring.security.user.password=123456
3、自定义实现类
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{
	@Autowired
    private UserDetailsService uds;  //注入用户服务信息
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        BCryptPasswordEncoder bpe = new BCryptPasswordEncoder();
        auth.userDetailsService(uds).passwordEncoder(bpe);
    }
}
@Service("uds")
public class MyUserDetailService implements UserDetailsService {
	@Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    	List<GrantedAuthority> authn = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin");
    	return new User("username",
                new BCryptPasswordEncoder().encode("123456"),authn);
	}
}

3)获取数据库用户信息以及对用户的增删改查以及授权(important)

1、查询数据库完成用户认证

这里需要整合mybatisPlus完成数据库操作或者jdbc

(1)引入相关依赖:
<!-- mybatis-Plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.0.5</version>
</dependency>
<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok简化实体类 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
(2)创建sql表格信息:

在这里插入图片描述

(3)配置实体类:
	package entity;

import lombok.Data;

public class Users {
    private int id;
    private String username;
    private String password;

    @Override
    public String toString() {
        return "Users{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public Users() {
    }

    public Users(int id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

(4)整合mp,创建接口,继承mp的接口
package com.hxzy.springscuritydamo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import entity.Users;
import org.springframework.stereotype.Repository;

/**
 * @BaseMapper 这个接口里实现了对数据库的增删改查操作,直接调用里面的方法就可以了
 * @Repository
 * */
@Repository
public interface UserMapper extends BaseMapper<Users> {}
(5)在MyUserDetailsService调用mapper里面的方法查询数据库进行用户认证
package com.hxzy.springscuritydamo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.hxzy.springscuritydamo.mapper.UserMapper;
import entity.Users;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service("uds")
public class MyUserDetailService implements UserDetailsService {

    @Autowired
    private UserMapper usersMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //调用userMapper方法,根据用户名查询数据库
        QueryWrapper<Users> wrapper = new QueryWrapper<>();
        wrapper.eq("username",username);
        Users users = usersMapper.selectOne(wrapper);
        //判断
        if (users == null){  //如果数据库里没有用户名,则认证失败
            throw new UsernameNotFoundException("用户不存在");
        }

        //查数据库,得到密码,得到用户名,得到s权限
        List<GrantedAuthority> authn = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_admin");
        return new User(users.getUsername(),
                new BCryptPasswordEncoder().encode(users.getPassword()),authn);
    }
}

(6)在启动类添加注解MapperScan
package com.hxzy.springscuritydamo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.hxzy.springscuritydamo.mapper")
@SpringBootApplication
public class SpringscuritydamoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringscuritydamoApplication.class, args);
    }

}

(7)数据库application.properties配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

2、自定义登录页面

(1)在配置类实现相关配置
package com.hxzy.springscuritydamo.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;
import java.beans.PersistenceDelegate;

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    private UserDetailsService uds;  //注入用户服务信息
    @Autowired
    private DataSource dataSource;//注入数据源
    //配置对象
    @Bean
    public PersistentTokenRepository ptr(){
        JdbcTokenRepositoryImpl jtr = new JdbcTokenRepositoryImpl();
        jtr.setDataSource(dataSource);
//        jtr.setCreateTableOnStartup(true);
        return jtr;
    }
//    @Override
//    public void addViewControllers(ViewControllerRegistry registry){
//        registry.addViewController("/").setViewName("forword:/login.html");
//        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
//    }
    //实现用户身份认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        BCryptPasswordEncoder bpe = new BCryptPasswordEncoder();
        auth.userDetailsService(uds).passwordEncoder(bpe);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置Url的权限访问
//        http.authorizeRequests()
//                .antMatchers("/").permitAll()
//                .antMatchers("/**update**").permitAll()
//                .antMatchers("login/**").permitAll()
//                .anyRequest().authenticated();
         http.csrf().disable();    //关闭csrf防护

        //配置没有访问权限页面403页面
        http.exceptionHandling().accessDeniedPage("/error.html");
        //安全退出
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/login").permitAll();
        //loginpage()->自定义登录页面设置,loginProcessingUrl()->登录访问的路径,defaultSuccessUrl()->登录成功后访问的页面
        http.formLogin().loginPage("/test/login")//自己配置的登录页面
                .loginProcessingUrl("/user/login")
                .defaultSuccessUrl("/test/index")
                .failureUrl("/test/error").permitAll()
                .and().authorizeRequests()
                .antMatchers("/","/test/hello","/user/login").permitAll() //设置哪些路径可以直接访问,不需要认证
                //1、hasAuthority:当前登录用户,只有具有admins权限的用户才能访问这个路径
                //.antMatchers("/test/index").hasAuthority("admins")
                //2、hasAnyAuthority:当前登录用户,自定义权限的用户才能访问这个路径
                //.antMatchers("/test/index").hasAnyAuthority("admins,manager")
                //3、hasRole:
                //.antMatchers("/test/index").hasRole("saler")
                //4、hasAnyRole:
                .antMatchers("/test/index").hasAnyRole("sale,manager,admin,user")
                .anyRequest().authenticated()
    }
}

(2)创建相关页面/test/login、/test/index

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            form{
                width: 240px;
            }
            span{
                display: block;
                margin-top: 10px;
            }
            input{
                float: right;
            }
        </style>
    </head>
    <body>
        <form action="/user/login" method="post">
<!--            <input th:name="${_csrf.parameterName}" th:value="${_csrf.token}" type="hidden"/>-->
            <span>用户名:<input type="text" name="username" /></span>
            <span>密码:<input type="password" name="password" /></span>
            <span>单点登录<input style="float: none" type="checkbox" name="remember-me" /></span>
            <input style="cursor: pointer;" type="submit" value="登录" />
        </form>
    </body>
</html>

3、web授权方案:用户授权(基于权限访问控制)

4个方法:hasAuthority()、hasAnyAuthority()、hasRole()、hasAnyRole()
(1)hasAuthority() —如果当前的主体具有指定的权限,有的话true,没有false
1:在配置类中设置当前访问地址有哪些权限
http.antMatchers("test/index").hasAuthortiy("admins")
2:在UserDetailsService,把返回User对象设置权限
List<GrantedAuthority> authn = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");

如果访问地址的权限与返回User对象权限不一致,则跳到403界面无权访问

(2)hasAnyAuthority() —如果当前的主体具有指定的权限,有的话true,没有false
1:在配置类中设置当前访问地址有哪些权限
.antMatchers("/test/index").hasAnyAuthority("admins,manager");
2:在UserDetailsService,把返回User对象设置任意在配置类中存在的权限
List<GrantedAuthority> authn = AuthorityUtils.commaSeparatedStringToAuthorityList("admins");
(3)hasRole() —如果当前用户为指定角色,则返回true在这里插入图片描述
(4)hasAnyRole() —如果当前用户为指定多个角色,则返回true在这里插入图片描述

4、web授权方案:自定义403无权访问界面

在配置类进行配置在这里插入图片描述

5、web授权方案:自定义安全退出操作

在配置类进行配置
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值