<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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.itheima</groupId> <artifactId>chapter071</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent> <dependencies> <!-- Spring Security提供的安全管理依赖启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</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> <!-- JDBC数据库连接启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- MySQL数据连接驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version><!--$NO-MVN-MAN-VER$ --> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- Spring Data JPA操作数据库 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>11</source> <target>11</target> </configuration> </plugin> </plugins> </build> </project>
server: port: 8082 spring: datasource: url: jdbc:mysql://localhost:3306/springbootdata?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8 username: root password: admin redis: host: 127.0.0.1 port: 6379 password:
package com.itheima.domain; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity(name = "t_authority ") public class Authority implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String authority; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getAuthority() { return authority; } public void setAuthority(String authority) { this.authority = authority; } @Override public String toString() { return "Authority{" + "id=" + id + ", authority='" + authority + '\'' + '}'; } }
package com.itheima.domain; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity(name = "t_customer") public class Customer implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String username; private String password; public Integer getId() { return id; } public void setId(Integer 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; } @Override public String toString() { return "Customer{" + "id=" + id + ", username='" + username + '\'' + ", password=" + password + '}'; } }
package com.itheima.repository; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import com.itheima.domain.Authority; public interface AuthorityRepository extends JpaRepository<Authority,Integer>{ @Query(value = "select a.* from t_customer c,t_authority a,t_customer_authority ca where ca.customer_id=c.id and ca.authority_id=a.id and c.username =?1",nativeQuery = true) public List<Authority> findAuthoritiesByUsername(String username); }
package com.itheima.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.itheima.domain.Customer; public interface CustomerRepository extends JpaRepository<Customer, Integer>{ Customer findByUsername(String username); }
package com.itheima.service; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import com.itheima.domain.Authority; import com.itheima.domain.Customer; import com.itheima.repository.AuthorityRepository; import com.itheima.repository.CustomerRepository; @Service public class CustomerService { @Autowired private CustomerRepository customerRepository; @Autowired private AuthorityRepository authorityRepository; @SuppressWarnings("rawtypes") @Autowired private RedisTemplate redisTemplate; // 业务控制:使用唯一用户名查询用户信息 @SuppressWarnings("unchecked") public Customer getCustomer(String username) { Customer customer = null; Object o = redisTemplate.opsForValue().get("customer_" + username); if (o != null) { customer = (Customer) o; } else { customer = customerRepository.findByUsername(username); if (customer != null) { redisTemplate.opsForValue().set("customer_" + username, customer); } } return customer; } // 业务控制:使用唯一用户名查询用户权限 @SuppressWarnings("unchecked") public List<Authority> getCustomerAuthority(String username) { List<Authority> authorities = null; Object o = redisTemplate.opsForValue().get("authorities_" + username); if (o != null) { authorities = (List<Authority>) o; } else { authorities = authorityRepository.findAuthoritiesByUsername(username); if (authorities.size() > 0) { redisTemplate.opsForValue().set("authorities_" + username, authorities); } } return authorities; } }
package com.itheima.service; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.SimpleGrantedAuthority; 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 com.itheima.domain.Authority; import com.itheima.domain.Customer; @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private CustomerService customerService; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { // 通过业务方法获取用户及权限信息 Customer customer = customerService.getCustomer(s); List<Authority> authorities = customerService.getCustomerAuthority(s); // 对用户权限进行封装 List<SimpleGrantedAuthority> list = authorities.stream() .map(authority -> new SimpleGrantedAuthority(authority.getAuthority())).collect(Collectors.toList()); // 返回封装的UserDetails用户详情类 if (customer != null) { UserDetails userDetails = new User(customer.getUsername(), customer.getPassword(), list); return userDetails; } else { // 如果查询的用户不存在(用户名不存在),必须抛出此异常 throw new UsernameNotFoundException("当前用户不存在!"); } } }
package com.itheima.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import com.itheima.service.UserDetailsServiceImpl; import javax.sql.DataSource; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DataSource dataSource; @Autowired private UserDetailsServiceImpl userDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 密码需要设置编码器 BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); // 1、使用内存用户信息,作为测试使用 // auth.inMemoryAuthentication().passwordEncoder(encoder).withUser("shitou").password(encoder.encode("123456")) // .roles("common").and().withUser("李四").password(encoder.encode("123456")).roles("vip"); // // 2、使用JDBC进行身份认证 // String userSQL = "select username,password,valid from t_customer " + "where username = ?"; // // String authoritySQL = "select c.username,a.authority from t_customer c,t_authority a," // + "t_customer_authority ca where ca.customer_id=c.id " + "and ca.authority_id=a.id and c.username =?"; // // auth.jdbcAuthentication().passwordEncoder(encoder).dataSource(dataSource).usersByUsernameQuery(userSQL) // .authoritiesByUsernameQuery(authoritySQL); // 3、使用UserDetailsService进行身份认证 auth.userDetailsService(userDetailsService).passwordEncoder(encoder); } }
package com.itheima.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @Controller public class FilmeController { // 影片详情页 @GetMapping("/detail/{type}/{path}") public String toDetail(@PathVariable("type") String type, @PathVariable("path") String path) { return "detail/" + type + "/" + path; } }
package com.itheima; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }