首頁  >  文章  >  Java  >  如何用SpringBoot+SpringSecurity實現基於真實資料的授權認證

如何用SpringBoot+SpringSecurity實現基於真實資料的授權認證

王林
王林轉載
2023-05-13 19:34:20909瀏覽

(一)概述

Spring Security是一個功能強大且高度可自訂的身份驗證和存取控制框架,Spring Security主要做兩個事情,認證、授權。我之前寫過一篇關於SpringSecurity的博客,但是當時只是介紹了基於mock數據的案例,本期就來介紹一下基於真實數據的認證授權實現。

(二)前期專案搭建

為了更好的展示SpringSecurity,我們先建造一個簡單的web專案出來。引入thymeleaf依賴

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-thymeleaf</artifactid>
</dependency>
<dependency>
    <groupid>org.thymeleaf</groupid>
    <artifactid>thymeleaf-spring5</artifactid>
</dependency>
<dependency>
    <groupid>org.thymeleaf.extras</groupid>
    <artifactid>thymeleaf-extras-java8time</artifactid>
</dependency>

新建一個登陸頁,一個首頁,然後幾個不同等級的展示頁面: login.html

nbsp;html>


    <meta>
    <title>登陆页</title>


<div>
    <form>
        <h3>登陆页</h3>
        <input>
        <input>
        <button>登陆</button>
    </form>
</div>

index.html

nbsp;html>


    <meta>
    <title>首页</title>


<div>
    <h3>首页</h3>
    <a>登陆</a>
    <div>
        <div>
            <h4>level1</h4>
            <a>level-1-1</a>
            <hr>
            <a>level-1-2</a>
        </div>
        <div>
            <h4>level2</h4>
            <a>level-2-1</a>
            <hr>
            <a>level-2-2</a>
        </div>
        <div>
            <h4>level3</h4>
            <a>level-3-1</a>
            <hr>
            <a>level-3-2</a>
        </div>
    </div>
</div>

另外還有幾個不同等級的頁面

如何用SpringBoot+SpringSecurity實現基於真實資料的授權認證 

分別在body中寫上自己對應的編號。

nbsp;html>


    <meta>
    <title>Title</title>


level-1-1

最後寫一個controller來接收請求:

@Controller
public class RouteController {

    @RequestMapping({"/","/index"})
    public String index(){
        return "index";
    }

    @RequestMapping("/login")
    public String toLogin(){
        return "login";
    }

    @RequestMapping("/level1/{id}")
    public String level1(@PathVariable("id")String id){
        return "level1/"+id;
    }
    @RequestMapping("/level2/{id}")
    public String level2(@PathVariable("id")String id){
        return "level2/"+id;
    }
    @RequestMapping("/level3/{id}")
    public String level3(@PathVariable("id")String id){
        return "level3/"+id;
    }
}

最終的效果如下:

如何用SpringBoot+SpringSecurity實現基於真實資料的授權認證 

最終實作等級不同的level頁面根據不同權限進行跳轉。

如何用SpringBoot+SpringSecurity實現基於真實資料的授權認證

後台基於Mybatis和Mysql資料庫實現,因此我們除了引入SpringSecurity的依賴之外,還需要引入Mybatis相關依賴:

<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-security</artifactid>
</dependency>
<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-jdbc</artifactid>
</dependency>
<dependency>
    <groupid>mysql</groupid>
    <artifactid>mysql-connector-java</artifactid>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupid>org.mybatis.spring.boot</groupid>
    <artifactid>mybatis-spring-boot-starter</artifactid>
    <version>2.1.3</version>
</dependency>

在設定文件中新增資料來源相關信息,以及Mybatis的配置:

spring.datasource.url=jdbc:mysql://localhost:3306/security?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mybatis.mapper-locations=classpath:mapper/*.xml

(三)認證與授權的實現

3.1 表結構設計

認證和授權在表設計上應該分在兩個表內,一個表存儲用戶信息包括密碼等,另一個表存儲授權信息,還需要一個表建立用戶和授權之間的關聯,給出最終的表結構:

CREATE TABLE `roles` (
  `id` int(4) NOT NULL,
  `rolename` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `sysuser` (
  `id` int(4) NOT NULL,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `user_role` (
  `id` int(4) NOT NULL,
  `user_id` int(4) DEFAULT NULL,
  `role_id` int(4) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

接下來是針對這三張表的實體類,Mapper介面以及xml文件,你可以不看程式碼,主要實作一個透過使用者名稱來尋找使用者以及相關權限的操作:

@Data
public class Roles {
    private Integer id;
    private String roleName;
}

@Data
public class SysUser {
    private Integer id;
    private String userName;
    private String password;
    private List<roles> roles;
}</roles>

Mapper介面:

public interface UserMapper {
    public SysUser getUserByUserName(@Param("userName") String userName);
}

xml實作:

<?xml  version="1.0" encoding="UTF-8" ?>
nbsp;mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper>
    <resultmap>
        <id></id>
        <result></result>
        <result></result>
        <collection>
            <result></result>
        </collection>
    </resultmap>
    <select>
        select sysuser.*,roles.rolename
        from sysuser
        LEFT JOIN user_role on sysuser.id= user_role.user_id
        LEFT JOIN roles on user_role.role_id=roles.id
        where username= #{userName}
    </select>
</mapper>

3.2 認證過程

SpringSecurity的認證過程是這樣的,首先透過用戶名或其他唯一的ID在資料庫裡找到這個用戶,用戶的密碼以非對稱加密的方式儲存。取到用戶後將前台傳入的密碼加密後和資料庫中已經加密好的欄位進行對比,從而通過認證。

上面這個過程中的第一步透過使用者名稱找到使用者的操作需要透過Service服務來實現,而這個Service服務需要繼承SpringSecurity中的UserDetailsS​​ervice介面。這個介面回傳一個SpringSecurity的User物件。

@Service
public class UserService implements UserDetailsService {

    @Resource
    private UserMapper userMapper;
    //根据用户名找到对应的用户信息
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        SysUser sysUser = userMapper.getUserByUserName(s);
        if (sysUser!=null){
            List<grantedauthority> roles=new ArrayList();
            sysUser.getRoles().stream().forEach(x->{
                roles.add(new SimpleGrantedAuthority(x.getRoleName()));
            });
            return new User(sysUser.getUserName(),sysUser.getPassword(),roles);
        }
        throw new UsernameNotFoundException("用户未找到");
    }
}</grantedauthority>

3.3 Security攔截設定

上面的步驟都完成後就開始設定Security了,寫一個設定方法SecurityConfig,程式碼層面很簡單,認證傳入userService對象,會自動把資料庫中取出的密碼和前端傳過來的密碼進行對照。同時在userService中也傳入了roles集合,在授權處為不同的頁面附上不同的權限即可。

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserService userService;
    //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //首页所有人都能访问,level页面只有有权限的人才能访问
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");
        //没有权限默认跳到登陆页,默认会重定向到/login
        http.formLogin();
    }

    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());

    }
}

3.4 其他注意點

我在認證的時候使用的密碼加密方式是BCryptPasswordEncoder,因此存入資料庫中的密碼也需要被加密,常用的方式就是在註冊時通過同樣的方式將密碼加密存入資料庫:

String password="xxx";
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
String encode=bCryptPasswordEncoder.encode(password);

以上是如何用SpringBoot+SpringSecurity實現基於真實資料的授權認證的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除