SpringSecurity數(shù)據(jù)庫進行認證和授權的使用
在前面的文章中,我們介紹了Spring Security基于內(nèi)存的一些基本使用方法,但在真實的業(yè)務場景中,用戶的賬號、密碼以及角色信息肯定都是存放在數(shù)據(jù)庫中的,所以我們需要從數(shù)據(jù)庫中來加載認證和授權的數(shù)據(jù)。
一、準備工作
如下案例是基于上一篇中的案例改造而來,所以建議先閱讀前一篇文章的內(nèi)容,將基本案例的代碼準備好。
1.1 導入相關依賴
除了引入security的依賴外,我們還需要引入數(shù)據(jù)庫驅動、連接池、MyBatis的依賴包:
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- security使用數(shù)據(jù)庫做驗證需要增加如下三個依賴 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
1.2 配置信息
我們需要在配置文件中增加數(shù)據(jù)源的配置信息,指定mapper xml的位置,這里改成你自己的位置即可。
# 配置數(shù)據(jù)源信息 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://x.x.x.x:3306/zhangxun?characterEncoding=utf-8&&serverTimezone=Asia/Shanghai&&useSSL=false spring.datasource.username=root spring.datasource.password=root # 配置mapper xml的位置 mybatis.mapper-locations=classpath:mapper/*Mapper.xml # 是否顯示執(zhí)行sql logging.level.com.xun.mapper=debug
1.3 數(shù)據(jù)庫準備
我們需要創(chuàng)建如下三張表,分別用來存儲用戶信息、角色信息、用戶與角色的對應關系。
CREATE TABLE `auth_user` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `user_name` varchar(100) DEFAULT NULL, `password` varchar(100) DEFAULT NULL, `expired` tinyint(1) DEFAULT NULL, `locked` tinyint(1) DEFAULT NULL, PRIMARY KEY (`user_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 -- 密文密碼的生成邏輯下面1.8節(jié)會講到,可以替換為自己密碼的密文進行插入 INSERT INTO zhangxun.auth_user (user_id, user_name, password, expired, locked) VALUES(1, 'root', '$2a$10$Hv037iGDdj82YjFORlYnyOdlra2EObV2XdddyW8A.r.Ph5ETOBNo2', 0, 0); INSERT INTO zhangxun.auth_user (user_id, user_name, password, expired, locked) VALUES(2, 'zhang', '$2a$10$cVgFLGx0Crz0Jf2TDBhJ.e6FS.BpH7YOoox2iSJrGW1DJ6OXiOt86', 0, 0); CREATE TABLE `auth_role` ( `role_id` int(11) NOT NULL AUTO_INCREMENT, `role_code` varchar(100) DEFAULT NULL, `role_name` varchar(100) DEFAULT NULL, PRIMARY KEY (`role_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4; INSERT INTO zhangxun.auth_role (role_id, role_code, role_name) VALUES(1, 'admin', '管理員'); INSERT INTO zhangxun.auth_role (role_id, role_code, role_name) VALUES(2, 'manager', '經(jīng)理'); CREATE TABLE `auth_user_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) DEFAULT NULL, `role_code` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4; -- root用戶將擁有admin和manager兩個角色,zhang用戶僅擁有manager一個角色 INSERT INTO zhangxun.auth_user_role (id, user_id, role_code) VALUES(1, 1, 'admin'); INSERT INTO zhangxun.auth_user_role (id, user_id, role_code) VALUES(2, 1, 'manager'); INSERT INTO zhangxun.auth_user_role (id, user_id, role_code) VALUES(3, 2, 'manager');
1.4 實體類的創(chuàng)建
@Data
public class Role {
private Integer roleId;
private String roleCode;
private String roleName;
}
@Data
public class User implements UserDetails {
private Integer userId;
private String userName;
private String password;
private Integer expired;
private Integer locked;
private List<Role> roles;
/**
* 獲取用戶的所有角色信息
* @return
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for(Role role : roles){
// 也可以在數(shù)據(jù)中添加角色時,就以 ROLE_ 開始,這樣就不用二次添加了
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleCode()));
}
return authorities;
}
/**
* 指定哪一個是用戶的密碼字段
* @return
*/
@Override
public String getPassword() {
return password;
}
/**
* 指定哪一個是用戶的賬戶字段
* @return
*/
@Override
public String getUsername() {
return userName;
}
/**
* 判斷賬戶是否過期
* @return
*/
@Override
public boolean isAccountNonExpired() {
return (expired == 0);
}
/**
* 判斷賬戶是否鎖定
* @return
*/
@Override
public boolean isAccountNonLocked() {
return (locked == 0);
}
/**
* 判斷密碼是否過期
* 可以根據(jù)業(yè)務邏輯或者數(shù)據(jù)庫字段來決定
* @return
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 判斷賬戶是否可用
* 可以根據(jù)業(yè)務邏輯或者數(shù)據(jù)庫字段來決定
* @return
*/
@Override
public boolean isEnabled() {
return true;
}
}
實現(xiàn)UserDetails接口的實體類會被認為是User實體,Spring Security會根據(jù)重寫的方法來加載用戶的必要信息:賬戶信息、密碼信息、賬戶過期、賬戶鎖定、密碼過期、賬戶啟用、賬戶擁有的角色信息。
1.5 Dao層的創(chuàng)建
@Mapper
public interface UserMapper {
User getUserByUserName(String userName);
List<Role> getUserRolesByUserId(Integer userId);
}
<?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.example.securitydemo.mapper.UserMapper">
<select id="getUserByUserName" parameterType="string" resultType="com.example.securitydemo.po.User">
select
au.user_id userId,
au.user_name userName,
au.password,
au.expired,
au.locked
from
auth_user au
where
au.user_name = #{userName}
</select>
<select id="getUserRolesByUserId" parameterType="integer" resultType="com.example.securitydemo.po.Role">
select
ar.role_id roleId,
ar.role_code roleCode,
ar.role_name roleName
from
auth_user_role aur
left join auth_role ar on
aur.role_code = ar.role_code
where
aur.user_id = #{userId}
</select
</mapper>
注意,如果UserMapper接口你是用了@Repository注解,那么就需要在啟動類上加上Mapper所在包的位置。
@MapperScan("com.example.securitydemo.mapper")
1.6 Service層的編寫
@Slf4j
@Service
public class UserService implements UserDetailsService {
@Resource
private UserMapper userMapper;
/**
* 根據(jù)用戶名去數(shù)據(jù)庫獲取用戶信息,SpringSecutity會自動進行密碼的比對
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 用戶名必須是唯一的,不允許重復
User user = userMapper.getUserByUserName(username);
if(ObjectUtils.isEmpty(user)){
throw new UsernameNotFoundException("根據(jù)用戶名找不到該用戶的信息!");
}
List<Role> roleList = userMapper.getUserRolesByUserId(user.getUserId());
user.setRoles(roleList);
return user;
}
}
1.7 Security配置
@EnableWebSecurity
public class DBSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
/**
* 對請求進行鑒權的配置
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 任何角色允許訪問
.antMatchers("/", "/index").permitAll()
// 僅admin角色可以訪問
.antMatchers("/admin/**").hasRole("admin")
// admin和manager兩個角色可以訪問
.antMatchers("/manager/**").hasAnyRole("admin", "manager")
.and()
// 沒有權限進入內(nèi)置的登錄頁面
.formLogin()
.and()
// 暫時關閉CSRF校驗,允許get請求登出
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
/**
* 默認開啟密碼加密,前端傳入的密碼Security會在加密后和數(shù)據(jù)庫中的密文進行比對,一致的話就登錄成功
* 所以必須提供一個加密對象,供security加密前端明文密碼使用
* @return
*/
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
1.8 密碼加密
@Slf4j
public class PasswordEncode {
private PasswordEncoder passwordEncoder;
@Before
public void before(){
this.passwordEncoder = new BCryptPasswordEncoder();
}
@Test
public void encodePassword(){
String rawPassword = "mm000";
String encodePassword = passwordEncoder.encode(rawPassword);
log.info("password:{} encoded is: {}", rawPassword, encodePassword);
}
}
該類是一個測試類,為了將明文密碼加密后得到密文的,密文存儲到User表的password字段。Spring Security默認開啟密碼加密功能的,數(shù)據(jù)庫加載出來的密碼會被進行格式校驗,如果不是合法的密文,登錄邏輯就會失敗。
1.9 測試結果
訪問localhost:8080/index無需登錄,直接就能返回結果。
訪問localhost:8080/admin/getHello將跳轉到登錄頁面,使用root賬戶(包含admin和manager兩個角色),隨便輸入一個密碼,登錄失敗;輸入正確的密碼,登錄成功后返回正確的內(nèi)容;此時再訪問localhost:8080/manager/getHello也能獲得正確的內(nèi)容。
調(diào)用localhost:8080/logout后將退出登錄,此時使用zhang賬戶(僅包含manager角色),輸入正確的密碼,登錄成功后返回正確的內(nèi)容;此時再訪問localhost:8080/admin/getHello將無法獲得內(nèi)容。
到此這篇關于SpringSecurity數(shù)據(jù)庫進行認證和授權的使用的文章就介紹到這了,更多相關SpringSecurity 數(shù)據(jù)庫認證和授權內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- SpringSecurity實現(xiàn)權限認證與授權的使用示例
- SpringSecurity進行認證與授權的示例代碼
- springSecurity用戶認證和授權的實現(xiàn)
- SpringBoot整合SpringSecurity認證與授權
- 深入淺析springsecurity入門登錄授權
- SpringSecurityOAuth2實現(xiàn)微信授權登錄
- SpringBoot+SpringSecurity實現(xiàn)基于真實數(shù)據(jù)的授權認證
- springsecurity第三方授權認證的項目實踐
- SpringSecurity授權機制的實現(xiàn)(AccessDecisionManager與投票決策)
相關文章
SpringBoot自定義注解使用讀寫分離Mysql數(shù)據(jù)庫的實例教程
這篇文章主要給大家介紹了關于SpringBoot自定義注解使用讀寫分離Mysql數(shù)據(jù)庫的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11
Java爬蟲實現(xiàn)爬取京東上的手機搜索頁面 HttpCliient+Jsoup
下面小編就為大家分享一篇Java爬蟲實現(xiàn)爬取京東上的手機搜索頁面 HttpCliient+Jsoup,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-11-11

