引入依赖:
<?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授权补充
- 建议使用基于资源的hasAuthority()方式,扩展性强
- 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>
密 码:
<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
数据库:
t_user
t_user_role
t_role_permission
t_role
t_permission
版权声明:本文为weixin_45957722原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。