pom
<?xml version="1.0" encoding="UTF-8"?>
<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.liaoxiang</groupId>
<artifactId>spring-security</artifactId>
<version>1.0.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
其他需要用到的後面再添加
權限控制涉及到主要資料庫表結構:

menu表為資源表,即使用者能通路的資源,url為背景接口的url pattern,将來用于和具體的請求進行對比,path為前端頁面路由路徑,component為具體元件,登陸成功之後,根據該使用者的角色資訊,擷取可以通路的資源菜單,渲染到頁面
其他的表資料為測試資料,不再叙述
在注釋掉springsecurity依賴的情況下,能夠通過接口正常擷取資料
在取消注釋之後,再次通路,跳轉到了一個登陸頁面
使用者名為:user ,密碼:日志中輸出的密碼
成功擷取資料
這裡使用的是Spring Security為我們生成的使用者名和密碼,下面我們使用自己資料中的使用者來登陸
建立一個service類
UserLoginService
,這個類要實作一個接口
UserDetailsService
,這是Spring Security處理使用者登陸的一個接口,實作接口裡的方法:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
這個方法接收一個使用者名,然後傳回一個實作了
UserDetails
接口的對象,下面看一下這個接口裡定義的内容:
public interface UserDetails extends Serializable {
//使用者權限(角色)的集合
Collection<? extends GrantedAuthority> getAuthorities();
//密碼
String getPassword();
//使用者名
String getUsername();
//賬戶是否未過期
boolean isAccountNonExpired();
//賬戶是否未鎖定
boolean isAccountNonLocked();
//密碼是否為過期
boolean isCredentialsNonExpired();
//賬戶是否激活
boolean isEnabled();
}
UserLoginService :
package com.liaoxiang.service;
import com.liaoxiang.mapper.UserMapper;
import com.liaoxiang.model.User;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* @auther Mr.Liao
* @date 2019/8/19 14:57
*/
@Service
public class UserLoginService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//如果User為null,就會抛出異常資訊:UsernameNotFoundException
User user = userMapper.findUserByUserName(username);
return user;
}
}
當執行
loadUserByUsername()
後,傳回一個
UserDetails
的實作類對象,Spring Security就會拿着上面這些資訊去判斷,密碼是否正确,幾個boolean傳回值的方法是否為true,進而來确定是否讓使用者登陸,而這些使用者的資訊應該都是我們資料庫中使用者的資訊,是以我們可以讓自己的使用者實體類來實作
UserDetails
接口:
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @auther Mr.Liao
* @date 2019/8/18 17:18
*/
@Data
@ToString
public class User implements UserDetails {
private Integer userId;
private String userName;
private String password;
private String name;
private List<Role> roles;
private boolean enabled;
/**
* 賬戶的權限資訊
* @return
*/
@JsonIgnore
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
ArrayList<GrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getRoleAuthority()));
}
return authorities;
}
@Override
public String getUsername() {
return userName;
}
@JsonIgnore
@Override
public boolean isAccountNonExpired() {
return true;
}
@JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
}
@JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
}
在處理使用者的權限資訊時,需要一個實作了
GrantedAuthority
接口的實作類對象,我們使用
SimpleGrantedAuthority
,它實作了
GrantedAuthority
,需要注意的是,在Spring Security中角色資訊以
ROLE_
開頭,是以在角色表中要使用注意角色的權限名稱:
public final class SimpleGrantedAuthority implements GrantedAuthority {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final String role;
public SimpleGrantedAuthority(String role) {
Assert.hasText(role, "A granted authority textual representation is required");
this.role = role;
}
@Override
public String getAuthority() {
return role;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof SimpleGrantedAuthority) {
return role.equals(((SimpleGrantedAuthority) obj).role);
}
return false;
}
@Override
public int hashCode() {
return this.role.hashCode();
}
@Override
public String toString() {
return this.role;
}
}
添加配置資訊:
userDetailsService
的實作類,和密碼加密解密工具類
BCryptPasswordEncoder
這個我們在啟動類中new了一個添加到IOC容器,在添加使用者時,加密了密碼,登陸時需要用來解密資料庫密碼和登陸時輸入的密碼進行比較
package com.liaoxiang.config;
import com.liaoxiang.service.UserLoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @auther Mr.Liao
* @date 2019/8/18 22:34
*/
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserLoginService userLoginService;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userLoginService)
.passwordEncoder(bCryptPasswordEncoder);
}
}
再次通過浏覽器通路擷取資料,跳轉到登陸頁,此時輸入使用者名和密碼就是添加使用者時的使用者名和密碼