Advertisement

springboot项目实战-基于JPA的Spring Boot Security操作

阅读量:

新建一个test17项目,具体步骤如下:

在pom.xml中配置Spring Security与JPA相关技术架构,默认场景下已集成MySQL等数据库服务。

复制代码
 <dependencies>

    
     <dependency>
    
         <groupId>org.springframework.boot</groupId>
    
         <artifactId>spring-boot-starter-web</artifactId>
    
     </dependency>
    
  
    
     <dependency>
    
         <groupId>org.springframework.boot</groupId>
    
         <artifactId>spring-boot-configuration-processor</artifactId>
    
         <optional>true</optional>
    
     </dependency>
    
     <dependency>
    
         <groupId>org.projectlombok</groupId>
    
         <artifactId>lombok</artifactId>
    
         <optional>true</optional>
    
     </dependency>
    
     <dependency>
    
         <groupId>org.springframework.boot</groupId>
    
         <artifactId>spring-boot-starter-test</artifactId>
    
         <scope>test</scope>
    
         <exclusions>
    
             <exclusion>
    
                 <groupId>org.junit.vintage</groupId>
    
                 <artifactId>junit-vintage-engine</artifactId>
    
             </exclusion>
    
         </exclusions>
    
     </dependency>
    
     <dependency>
    
         <groupId>org.springframework.boot</groupId>
    
         <artifactId>spring-boot-starter-data-jpa</artifactId>
    
     </dependency>
    
     <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.thymeleaf.extras</groupId>
    
         <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    
     </dependency>
    
     <dependency>
    
         <groupId>mysql</groupId>
    
         <artifactId>mysql-connector-java</artifactId>
    
         <version>5.1.47</version>
    
     </dependency>
    
     <dependency>
    
         <groupId>cn.hutool</groupId>
    
         <artifactId>hutool-all</artifactId>
    
         <version>5.3.7</version>
    
     </dependency>
    
     </dependencies>

(2)为了增强项目的开发多样性,在本次开发中采用了yaml格式的配置文件。具体来说,在application.yml中新增了项目相关配置项用于设定数据库连接参数。同时,在sys数据库方面提供了详细的配置信息如下:

复制代码
 server.port=8089

    
 spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    
 spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimeZone=Asia/Shanghai
    
 spring.datasource.username=root
    
 spring.datasource.password=mysql123
    
  
    
 spring.jpa.hibernate.ddl-auto=update
    
 spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
    
 spring.jpa.open-in-view=false
    
 spring.main.allow-circular-references=true

(3)开始编写项目代码,新建Security的配置文件WebSecurityConfig.java:

复制代码
 package com.shrimpking;

    
  
    
 import org.springframework.beans.factory.annotation.Autowired;
    
 import org.springframework.context.annotation.Bean;
    
 import org.springframework.context.annotation.Configuration;
    
 import org.springframework.security.authentication.AuthenticationProvider;
    
 import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
    
 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.UserDetailsService;
    
 import org.springframework.security.crypto.factory.PasswordEncoderFactories;
    
 import org.springframework.security.crypto.password.NoOpPasswordEncoder;
    
 import org.springframework.security.crypto.password.PasswordEncoder;
    
 import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
    
 import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
    
  
    
 import javax.sql.DataSource;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 20:52
    
  */
    
 @Configuration
    
 @EnableGlobalMethodSecurity(securedEnabled = true)
    
 public class WebSecurityConfig extends WebSecurityConfigurerAdapter
    
 {
    
     @Autowired
    
     private UserDetailService userDetailsService;
    
  
    
     @Autowired
    
     private PersistentTokenRepository persistentTokenRepository;
    
  
    
     @Override
    
     protected void configure(AuthenticationManagerBuilder auth) throws Exception
    
     {
    
     auth.authenticationProvider(authenticationProvider());
    
     }
    
  
    
     @Override
    
     protected void configure(HttpSecurity http) throws Exception
    
     {
    
     //关闭csrf
    
     http.csrf().disable();
    
     //自定义登录页面
    
     http.formLogin().loginPage("/loginPage")
    
             //登录访问路径,只需定义url即可
    
             .loginProcessingUrl("/login")
    
             //登录失败的路径
    
             .failureUrl("/exception")
    
             //
    
             .defaultSuccessUrl("/index",true);
    
     //
    
     http.authorizeRequests()
    
             //放行名单
    
             .antMatchers("/loginPage","/hello","/exception","/*.jpg").permitAll()
    
             //其他认证才可以访问
    
             .anyRequest().authenticated();
    
     //注销
    
     http.logout().logoutUrl("/logout");
    
     //记住我
    
     http.rememberMe()
    
             //token
    
             .tokenRepository(persistentTokenRepository)
    
             //token过期时间
    
             .tokenValiditySeconds( 60 * 60 )
    
             .userDetailsService(userDetailsService);
    
     }
    
  
    
     /** * 登录提示
    
      * @return
    
      */
    
     @Bean
    
     public AuthenticationProvider authenticationProvider(){
    
     DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    
     //显示用户找不到异常,默认不论用户名或密码哪个错误,都提示密码错误
    
     provider.setHideUserNotFoundExceptions(false);
    
     provider.setPasswordEncoder(passwordEncoder());
    
     provider.setUserDetailsService(userDetailsService);
    
     return provider;
    
     }
    
  
    
     /** * 密码加密器
    
      * @return
    
      */
    
     @Bean
    
     public PasswordEncoder passwordEncoder(){
    
  
    
     //return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    
     return NoOpPasswordEncoder.getInstance();
    
     }
    
  
    
     @Bean
    
     public PersistentTokenRepository persistentTokenRepository(DataSource dataSource){
    
     JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
    
     jdbcTokenRepository.setDataSource(dataSource);
    
     return jdbcTokenRepository;
    
     }
    
 }

(4)新建Web请求的UserControllerjava入口文件,并定义其访问的URL:

复制代码
 package com.shrimpking;

    
  
    
 import lombok.extern.slf4j.Slf4j;
    
 import org.springframework.security.access.annotation.Secured;
    
 import org.springframework.stereotype.Controller;
    
 import org.springframework.web.bind.annotation.GetMapping;
    
 import org.springframework.web.bind.annotation.ResponseBody;
    
 import org.springframework.web.util.WebUtils;
    
  
    
 import javax.security.sasl.AuthenticationException;
    
 import javax.servlet.http.HttpServletRequest;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 21:09
    
  */
    
 @Controller
    
 @Slf4j
    
 public class UserController
    
 {
    
     @ResponseBody
    
     @GetMapping("/hello")
    
     public String hello(){
    
     return "hello";
    
     }
    
  
    
     /** * 登录页面
    
      * @return
    
      */
    
     @GetMapping("/loginPage")
    
     public String login(){
    
     return "login";
    
     }
    
  
    
     /** * 认证异常
    
      * @param request
    
      * @return
    
      */
    
     @GetMapping("/exception")
    
     public String error(HttpServletRequest request) throws AuthenticationException
    
     {
    
     AuthenticationException exception
    
             = (AuthenticationException)WebUtils.getSessionAttribute(request, "SPRING_SECURITY_LAST_EXCEPTION");
    
     if(exception != null){
    
         throw exception;
    
     }
    
     return "redierct:/loginPage";
    
     }
    
  
    
     @GetMapping({"/index","/"})
    
     public String index(){
    
     return "index";
    
     }
    
  
    
     @ResponseBody
    
     @GetMapping("/role/teacher")
    
     @Secured({"ROLE_teacher","ROLE_admin"})
    
     public String teacher(){
    
     return "模拟获取教师数据";
    
     }
    
  
    
     @ResponseBody
    
     @GetMapping("/role/admin")
    
     @Secured({"ROLE_admin"})
    
     public String admin(){
    
     return "模拟获取管理员数据";
    
     }
    
  
    
     @ResponseBody
    
     @GetMapping("/role/student")
    
     @Secured({"ROLE_student","ROLE_admin"})
    
     public String student(){
    
     return "模拟获取学生数据";
    
     }
    
 }

(5)新建UserDao.java文件和AuthoritiesDao.java文件进行数据库的操作。

复制代码
 package com.shrimpking;

    
  
    
 import org.springframework.data.jpa.repository.JpaRepository;
    
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 21:39
    
  */
    
 public interface AuthoritiesDao extends JpaRepository<Authorities,Integer>, JpaSpecificationExecutor<Authorities>
    
 {
    
  
    
 }
复制代码
 package com.shrimpking;

    
  
    
 import org.springframework.data.jpa.repository.JpaRepository;
    
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 21:20
    
  */
    
 public interface UsersDao extends JpaRepository<Users,Integer>,JpaSpecificationExecutor<Users>
    
 {
    
     Users findByUsername(String username);
    
 }

(6)新建数据库的表对应的实体类Authorities、PersistentLogins和Users。

复制代码
 package com.shrimpking;

    
  
    
 import lombok.Data;
    
  
    
 import javax.persistence.CascadeType;
    
 import javax.persistence.Entity;
    
 import javax.persistence.GeneratedValue;
    
 import javax.persistence.GenerationType;
    
 import javax.persistence.Id;
    
 import javax.persistence.ManyToMany;
    
 import javax.persistence.Table;
    
 import java.util.HashSet;
    
 import java.util.Set;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 21:26
    
  */
    
 @Data
    
 @Entity
    
 @Table(name = "ao_authorities")
    
 public class Authorities
    
 {
    
     @Id
    
     @GeneratedValue(strategy = GenerationType.IDENTITY)
    
     private Integer id;
    
  
    
     private String authority;
    
     @ManyToMany(mappedBy = "authorities",cascade = CascadeType.ALL)
    
     private Set<Users> users = new HashSet<>();
    
 }
复制代码
 package com.shrimpking;

    
  
    
 import lombok.Data;
    
  
    
 import javax.persistence.Column;
    
 import javax.persistence.Entity;
    
 import javax.persistence.Id;
    
 import javax.persistence.Table;
    
 import java.util.Date;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 21:29
    
  */
    
 @Data
    
 @Entity
    
 @Table(name = "ao_persistent_logins")
    
 public class PersistentLogins
    
 {
    
     @Id
    
     private String series;
    
     private String username;
    
     private String token;
    
     @Column(name = "last_used")
    
     private Date lastUsed;
    
 }
复制代码
 package com.shrimpking;

    
  
    
 import lombok.Data;
    
  
    
 import javax.persistence.CascadeType;
    
 import javax.persistence.Entity;
    
 import javax.persistence.GeneratedValue;
    
 import javax.persistence.GenerationType;
    
 import javax.persistence.Id;
    
 import javax.persistence.JoinColumn;
    
 import javax.persistence.JoinTable;
    
 import javax.persistence.ManyToMany;
    
 import javax.persistence.Table;
    
 import java.util.HashSet;
    
 import java.util.Set;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 21:22
    
  */
    
 @Data
    
 @Entity
    
 @Table(name = "ao_users")
    
 public class Users
    
 {
    
     @Id
    
     @GeneratedValue(strategy = GenerationType.IDENTITY)
    
     private Integer id;
    
  
    
     private String username;
    
  
    
     private String password;
    
  
    
     @ManyToMany(targetEntity = Authorities.class,cascade = CascadeType.ALL)
    
     @JoinTable(name = "ao_users_authorities",
    
         joinColumns = @JoinColumn(name = "users_id",referencedColumnName = "id"),
    
     inverseJoinColumns = @JoinColumn(name = "authorities_id",referencedColumnName = "id"))
    
     private Set<Authorities> authorities = new HashSet<>();
    
 }
复制代码
 drop table if exists ao_user;

    
 create table ao_user(
    
 	id bigint not null auto_increment primary key comment '主键id',
    
 	user_name varchar(50) not null unique comment '用户名',
    
 	password varchar(100) default null comment '密码',
    
 	age int default null comment '年龄'
    
 ) comment '用户表';
    
  
    
 drop table if exists ao_users;
    
 create table ao_users(
    
 	id int not null auto_increment primary key comment '主键id',
    
 	username varchar(100) not null comment '用户名',
    
 	password varchar(255) not null comment '密码'
    
 ) comment '用户表2';
    
 insert into ao_users values(1,'admin','123456');
    
  
    
 drop table if exists ao_authorities;
    
 create table ao_authorities(
    
 	id int not null auto_increment primary key comment '主键id',
    
 	authority varchar(200) not null comment '授权'
    
 ) comment '权限表';
    
  
    
 drop table if exists ao_users_authorities;
    
 create table ao_users_authorities(
    
 	id int not null auto_increment primary key comment '主键id',
    
 	users_id int not null comment '用户id',
    
 	authorities_id int not null comment '权限id'
    
 ) comment '用户权限关系表';
    
  
    
 drop table if exists ao_persistent_logins;
    
 create table ao_persistent_logins(
    
 	series varchar(100) not null primary key comment '主键',
    
 	username varchar(100) default null comment '用户名',
    
 	token varchar(255) default null comment '令牌',
    
 	last_used datetime default CURRENT_TIMESTAMP comment '最近登录时间'
    
 ) comment '保持登录';

(7)设置项目的全局异常处理:

复制代码
 package com.shrimpking;

    
  
    
 import lombok.extern.slf4j.Slf4j;
    
 import org.springframework.security.authentication.BadCredentialsException;
    
 import org.springframework.web.bind.annotation.ControllerAdvice;
    
 import org.springframework.web.bind.annotation.ExceptionHandler;
    
 import org.springframework.web.servlet.ModelAndView;
    
  
    
 import java.nio.file.AccessDeniedException;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 21:41
    
  */
    
 @ControllerAdvice
    
 @Slf4j
    
 public class GlobalExceptionHandler
    
 {
    
     @ExceptionHandler(RuntimeException.class)
    
     public ModelAndView exception(Exception e){
    
     log.info(e.toString());
    
     ModelAndView modelAndView = new ModelAndView();
    
     modelAndView.setViewName("error");
    
     if(e instanceof BadCredentialsException){
    
         //密码错误
    
         modelAndView.addObject("msg","密码错误");
    
     }else if( e instanceof AccessDeniedException){
    
         //权限不足
    
         modelAndView.addObject("msg",e.getMessage());
    
     }else {
    
         modelAndView.addObject("msg","系统错误");
    
     }
    
     return modelAndView;
    
     }
    
 }

(8)设置用户的服务类,代码如下:

复制代码
 package com.shrimpking;

    
  
    
 import lombok.extern.slf4j.Slf4j;
    
 import org.springframework.beans.factory.annotation.Autowired;
    
 import org.springframework.security.core.GrantedAuthority;
    
 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 org.springframework.transaction.annotation.Transactional;
    
  
    
 import java.util.ArrayList;
    
 import java.util.Set;
    
  
    
 /** * Created by IntelliJ IDEA.
    
  * * @Author : Shrimpking
    
  * @create 2023/11/19 21:46
    
  */
    
 @Service("userDetailsService")
    
 @Slf4j
    
 public class UserDetailService implements UserDetailsService
    
 {
    
     @Autowired
    
     private UsersDao usersDao;
    
  
    
     @Override
    
     @Transactional()
    
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
    
     {
    
     Users users = usersDao.findByUsername(username);
    
     if(users == null){
    
         log.error("用户名:[{}]不存在",username);
    
         throw new UsernameNotFoundException("用户名不存在");
    
     }
    
     Set<Authorities> authoritiesSet = users.getAuthorities();
    
     ArrayList<GrantedAuthority> list = new ArrayList<>();
    
     for (Authorities authorities : authoritiesSet)
    
     {
    
         list.add(new SimpleGrantedAuthority(authorities.getAuthority()));
    
     }
    
     return new User(users.getUsername(),users.getPassword(),list);
    
     }
    
 }

(9)新建Spring Boot项目的启动类:

复制代码
 package com.shrimpking;

    
  
    
 import org.springframework.boot.SpringApplication;
    
 import org.springframework.boot.autoconfigure.SpringBootApplication;
    
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    
  
    
 @SpringBootApplication
    
 @EnableWebSecurity
    
 public class Test17SecurityjpaApplication
    
 {
    
  
    
     public static void main(String[] args)
    
     {
    
     SpringApplication.run(Test17SecurityjpaApplication.class, args);
    
     }
    
  
    
 }
复制代码
 <!DOCTYPE html>

    
 <html xmlns:th="http://www.thymeleaf.org">
    
 <head>
    
     <meta charset="UTF-8">
    
     <title>请登录</title>
    
 </head>
    
 <body>
    
 <div>
    
     <form action="/login" th:action="@{/login}" method="post">
    
     <p>
    
         <span>请输入用户名:</span>
    
         <input type="text" id="username" name="username">
    
     </p>
    
     <p>
    
         <span>请输入密码:</span>
    
         <input type="password" id="password" name="password">
    
     </p>
    
     <input type="submit" value="登录">
    
     </form>
    
 </div>
    
 </body>
    
 </html>
复制代码
 <!DOCTYPE html>

    
 <html xmlns:th="http://www.thymeleaf.org">
    
 <head>
    
     <meta charset="UTF-8">
    
     <title>主页</title>
    
 </head>
    
 <body>
    
 你已经登录成功!
    
 <form action="/loginPage" th:action="@{/logout}" method="post">
    
     <input type="submit" value="退出系统">
    
 </form>
    
 </body>
    
 </html>
复制代码
 <!DOCTYPE html>

    
 <html xmlns:th="http://www.thymeleaf.org">
    
 <head>
    
     <meta charset="UTF-8">
    
     <title>页面</title>
    
 </head>
    
 <body>
    
 hello页面
    
 </body>
    
 </html>

应在启动项目之前做好数据库的配置工作。本书使用MySQL 5。配置信息的具体位置设置于application.properties文件中。建议读者根据实际需求自行调整相关参数。经确认无误后便可开始项目搭建工作。

访问该页面即可观察到登录界面。通过输入账号admin和密码123456完成登录操作后,则能够查看到相应的权限设置。

全部评论 (0)

还没有任何评论哟~