基于springboot与spring security访问数据库的认证与授权

引入依赖:

<?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.1.3.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.itheima.security</groupId>
    <artifactId>demo-security-springboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-security-springboot</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.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>

<!--        <!‐‐jsp页面使用jstl标签 ‐‐>-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
<!--        <!‐‐用于编译jsp ‐‐>-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.0</version>
        </dependency>

<!--        mysql依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
<!--            <version>5.1.25</version>-->
            <version>8.0.19</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>


            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>utf‐8</encoding>
                    <useDefaultDelimiters>true</useDefaultDelimiters>
                    <resources>
                        <resource>
                            <directory>src/main/resources</directory>
                            <filtering>true</filtering>
                            <includes>
                                <include>**/*</include>
                            </includes>
                        </resource>
                        <resource>
                            <directory>src/main/java</directory>
                            <includes>
                                <include>**/*.xml</include>
                            </includes>
                        </resource>
                    </resources>
                </configuration>
            </plugin>
        </plugins>

    </build>

</project>

spring boot启动类

package com.itheima.security.demosecurityspringboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

}

application.properties:

#基础配置
server.port=8080
server.servlet.context‐path=/springboot-security
spring.application.name = security‐springboot

#spring-mvc试图解析器
spring.mvc.view.prefix=/WEBINF/view/
spring.mvc.view.suffix=.jsp

#mysql驱动配置 本人mysql5.7 如果版本低就在pom文件导入版本低的依赖 如:5.1.44  com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=UTF8&serverTimezone=UTC&useSSL=false
spring.datasource.username=root
spring.datasource.password=huang
spring.datasource.driver‐class‐name=com.mysql.cj.jdbc.Driver

spring Context配置

package com.itheima.security.demosecurityspringboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
//			此处使用了自定义的登陆界面:
        registry.addViewController("/").setViewName("redirect:/login-view");
        registry.addViewController("/login-view").setViewName("login");
// 			security提供的登陆界面:
//        registry.addViewController("/").setViewName("redirect:/login");
    }
}

spring-security安全配置

package com.itheima.security.demosecurityspringboot.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)//此注解用于使用“基于方法”的授权方式
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

//用户信息配置,在service包中配置了userDeatilService实现UserDetailService的类,
    /*@Bean
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("zhangsan").password("123").authorities("p1").build());
        manager.createUser(User.withUsername("lisi").password("456").authorities("p2").build());
        return manager;
    }
*/
//密码编码器  可以判断用此编码器  加密的密码字段  有自己的规则
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

//安全拦截机制
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()  //关于security防止跨站请求伪造 的解决方案
                .authorizeRequests()  //允许基于使用HttpServletRequest限制访问
                .antMatchers("/r/r1").hasAuthority("p1")  //使用Web授权 拥有权限p1才可以访问/r/r1
                .antMatchers("/r/r2").hasAuthority("p2")  //
                .antMatchers("/r/**").authenticated()     //访问/r/** 都是需要权限  登录认证 在获取是否有访问的权限  
                .anyRequest().permitAll()
                .and()
                .formLogin()
                    .loginPage("/login-view") // 自定义登陆界面
                    .loginProcessingUrl("/login")  // 自定义登陆界面
                    .successForwardUrl("/login-success");
    }
}

web授权补充

  1. 建议使用基于资源的hasAuthority()方式,扩展性强
  2. antMatchers(),具体的url地址写在非具体的前面

LoginController:

package com.itheima.security.demosecurityspringboot.controller;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class LoginController {
    @RequestMapping(value = "/login-success",produces = {"text/plain;charset=UTF-8"})
    public String loginsuccess(){
        String username = getUsername();
        return username+"登陆成功";
    }

//获取登陆用户的信息
    private String getUsername() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(!authentication.isAuthenticated()){
            return null;
        }

        Object principal = authentication.getPrincipal();
        String username =null;

        if(principal instanceof org.springframework.security.core.userdetails.UserDetails){
            username = ((UserDetails) principal).getUsername();
        }else {
            username = principal.toString();
        }
        return username;
    }

//    @PreAuthorize("hasAuthority('p1')")  基于方法的授权方式 使用注解
    @GetMapping(value = "/r/r1",produces = {"text/plain;charset=UTF-8"})
    public String r1(){
        String username = getUsername();
        return username+"访问资源1";
    }

//    @PreAuthorize("hasAuthority('p2')")
    @GetMapping(value = "/r/r2",produces = {"text/plain;charset=UTF-8"})
    public String r2(){
        String username = getUsername();
        return username+"访问资源2";
    }
}

用户实体UserDto:

package com.itheima.security.demosecurityspringboot.model;

import lombok.Data;

// lombok提供的注解 用来获取get/set方法!!!!
@Data
public class UserDto {
    private String id;
    private String username;
    private String password;
    private String fullname;
    private String mobile;

}

权限实体PermissionDto:

package com.itheima.security.demosecurityspringboot.model;

import lombok.Data;

@Data
public class PermissionDto {
    private String id;
    private String code;
    private String description;
    private String url;
}

UserDao

package com.itheima.security.demosecurityspringboot.dao;

import com.itheima.security.demosecurityspringboot.model.PermissionDto;
import com.itheima.security.demosecurityspringboot.model.UserDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

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

@Repository
public class UserDao {
//自动装配
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public UserDto getUserByUsername(String username) {
        String sql = "select * from t_user where username = ?";
        List<UserDto> list = jdbcTemplate.query(sql, new Object[]{username}, new BeanPropertyRowMapper<>(UserDto.class));
        if (list == null && list.size() <= 0) {
            return null;
        }
        return list.get(0);
    }

    public List<String> findPermissionByUeserId(String userId){
        String sql = "SELECT * FROM t_permission WHERE id IN" +
                "(SELECT permission_id FROM t_role_permission WHERE role_id IN" +
                "(SELECT role_id from t_user_role WHERE user_id = ?))";

        List<PermissionDto> list = jdbcTemplate.query(sql, new Object[]{userId}, new BeanPropertyRowMapper<>(PermissionDto.class));
        List<String> array = new ArrayList<String>();

//Lambda表达式遍历集合
//        list.iterator().forEachRemaining(c->array.add(c.getCode()));
        list.forEach(c->array.add(c.getCode()));

        return array;
    }
}

userDetailService

package com.itheima.security.demosecurityspringboot.service;

import com.itheima.security.demosecurityspringboot.dao.UserDao;
import com.itheima.security.demosecurityspringboot.model.UserDto;
import org.springframework.beans.factory.annotation.Autowired;
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.stereotype.Service;

import java.util.List;

@Service
public class userDetailService implements UserDetailsService {
    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("username:" + username);
        UserDto userDto = userDao.getUserByUsername(username);
        if (userDto == null) {
            return null;
        }

        String userDtoId = userDto.getId();

        List<String> permission = userDao.findPermissionByUeserId(userDtoId);
        String[] strings = new String[permission.size()];

        permission.toArray(strings);
//用户信息配置  账户 密码 权限....
        UserDetails userDetails = User.withUsername(userDto.getUsername()).password(userDto.getPassword()).authorities(strings).build();
        return userDetails;
    }
}

自定义登陆界面

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" language="java" %>
<html>
<head>
    <title>用户登录</title>
</head>
<body>
<form action="login" method="post">
    用户名:<input type="text" name="username"><br>&nbsp;&nbsp;&nbsp;码:
    <input type="password" name="password"><br>
    <input type="submit" value="登录">
</form>
</body>
</html>


在这里插入图片描述

数据库:

在这里插入图片描述

t_user

t_user

t_user_role

t_user_role
t_role_permission
t_role_Permission

t_role

在这里插入图片描述

t_permission

在这里插入图片描述


版权声明:本文为weixin_45957722原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。