聽說微信搜索《Java魚仔》會變更強!
本文收錄于JavaStarter ,里面有我完整的Java系列文章,學習或面試都可以看看哦
(一)概述
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陸頁</title>
</head>
<body>
<div>
<form>
<h2>登陸頁</h2>
<input type="text" id="username" placeholder="username">
<input type="password" id="password" placeholder="password">
<button type="button">登陸</button>
</form>
</div>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首頁</title>
</head>
<body>
<div>
<h2>首頁</h2>
<a href="/login">登陸</a>
<div style="overflow: hidden">
<div style="float: left;margin-left: 20px">
<h3>level1</h3>
<a href="/level1/1">level-1-1</a>
<hr>
<a href="/level1/2">level-1-2</a>
</div>
<div style="float: left;margin-left: 20px">
<h3>level2</h3>
<a href="/level2/1">level-2-1</a>
<hr>
<a href="/level2/2">level-2-2</a>
</div>
<div style="float: left;margin-left: 20px">
<h3>level3</h3>
<a href="/level3/1">level-3-1</a>
<hr>
<a href="/level3/2">level-3-2</a>
</div>
</div>
</div>
</body>
</html>
另外還有幾個不同等級的頁面

分別在body中寫上自己對應的編號,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
level-1-1
</body>
</html>
最后撰寫一個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;
}
}
最終的效果如下:

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

后臺基于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;
}
Mapper介面:
public interface UserMapper {
public SysUser getUserByUserName(@Param("userName") String userName);
}
xml實作:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.javayz.springsecurity.mapper.UserMapper">
<resultMap id="userMap" type="com.javayz.springsecurity.entity.SysUser">
<id property="id" column="ID"/>
<result property="userName" column="username"/>
<result property="password" column="password"/>
<collection property="roles" ofType="com.javayz.springsecurity.entity.Roles">
<result column="name" property="roleName"/>
</collection>
</resultMap>
<select id="getUserByUserName" parameterType="String" resultMap="userMap">
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中的UserDetailsService介面,這個介面回傳一個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("用戶未找到");
}
}
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);
(四)總結
SpringSecurity很強大,除了這種方式之外,還支持集成JWT、Oauth2等等,后續我會繼續更新,我是魚仔,我們下期再見,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/282148.html
標籤:其他
