養成習慣,先贊后看!!!
目錄
- 1.前言
- 2.流程
- 2.1匯入依賴
- 2.2用戶物體類實作UserDetails
- 2.3用戶業務層實作UserDetailsService
- 2.4撰寫SpringSecurity的配置類SecurityConfig
- 3.效果演示
1.前言
之前專案用的是SSM框架,所以我們選用的安全框架是shiro,但是因為技術主管把我們分散做的模塊整合到一起做成微服務的形式,所以我們就用springboot重新將我們的專案遷移了過來.
之后改吧改吧,把大部分的邏輯全部都遷移過來了,之后就是加入安全框架了,因為現在使用的springboot,所以我們選擇使用springsecurity這個安全框架,雖然說springboot能夠和springsecurity完美配合,但是就算這樣,up還是搞了一天才把整個的安全框架嵌了進來.究其原因,還是up自己太菜了.

行了話不多說,這里把完整的教程貢獻出來,希望對你有所幫助.
2.流程
其實整個流程還是比較簡單的,畢竟都是spring一家的,所以適配起來,的確相對來說比較的簡單.
其實主要就分為三個部分,這三個部分分別是 UserDetails UserDetailsService 和SecurityConfig
- UserDetails
因為我們最后都是需要從資料庫里面讀取賬戶資訊的,所以我們需要在我們定義的用戶物體類中實作UserDetails介面中的一些方法,這其中主要就是包括用戶 角色,權限 那部分的資訊. - UserDetailsService
其實大家看到Service就知道是什么意思了,就是需要我們將我們在對應的UserService中實作UserDetailsService的方法,主要就是實作用戶的 認證授權 操作 - SecurityConfig
這個一看名字就知道是組態檔了.這里主要配置 密碼的加密方式,HTTP過濾 等功能
接下來就是詳細的教程了
2.1匯入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2.2用戶物體類實作UserDetails
這里我們點進來看一下,發現UserDetails里面主要是下面這幾個屬性:

這里我們主要將一下這幾個屬性的含義
- Collection<? extends GrantedAuthority> getAuthorities();//用戶的
權限集 - String getPassword();//用戶的加密后的
密碼 - String getUsername();//應用內
唯一的用戶名 - boolean isAccountNonExpired();//賬戶是否過期
- boolean isAccountNonLocked();//賬戶是否鎖定
- boolean isCredentialsNonExpired();//憑證是否過期
- boolean isEnabled();//用戶是否可用
當我們繼承了UserDetails這個介面之后我們就需要重寫上述的所有方法,同下面的代碼:
private Collection<? extends GrantedAuthority> authorities;//這里說是權限集,其實里面存放的其實是用戶的角色資訊,并且是字串的形式
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;//這里的回傳型別是固定的,不能修改成你自己定義的角色物件
}
@Override
public String getUsername() {
return loginName;//這里回傳你自己定義的唯一用戶名的白能量名稱
}
//下面四個默認都回傳true就行了
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
2.3用戶業務層實作UserDetailsService
這里我們需要將我們的UserService繼承UserDetailsService,然后去實作他里面的方法,這里我們點進原始碼看了之后發現,他里面就一個方法

這里我們重寫一下他的這個方法
@SneakyThrows
@Override
public UserDao loadUserByUsername(String username) throws AuthenticationException {
//首先通過用戶名查詢是否有該用戶
UserDao userDao=userDaoMapper.getUserByLoginName(username);
//System.out.println(userDao);
//如果用戶存在就開始執行身份認證以及授權的相關操作
if(userDao!=null)
{
// HttpSession session = request.getSession();
// session.setAttribute("userDao",userDao);
// session.setAttribute("sessusername",username);
//這里是判斷用戶的狀態即是否鎖定
if(userDao.getState()==0)
{
throw new AccountLockedException("賬戶已鎖定!");
}
else {
List<GrantedAuthority> authorities = new ArrayList<>();
//查詢出來該用戶的角色串列
List<RoleDao> roleDaoList=roleService.getRoleByUserId(userDao.getUserId());
//權限串列
List<RightDao> rightDaoList=new ArrayList<>();
for(RoleDao roleDao:roleDaoList)
{
authorities.add(new SimpleGrantedAuthority("ROLE_"+roleDao.getName()));
for(RightDao rightDao:rightService.getRightsByRoleId(roleDao.getRoleId()))
{
rightDaoList.add(rightDao);
}
}
// System.out.println(username+"用戶已經登錄");
// System.out.println("有以下角色");
// for(GrantedAuthority a:authorities)
// System.out.println(a);
// System.out.println("有以下權限");
// for(RightDao rightDao:rightDaoList)
// System.out.println(rightDao);
return new UserDao(username,userDao.getPassword(),authorities,rightDaoList);
}
}
else
{
throw new UsernameNotFoundException("用戶名不存在!");
}
}
這里面有幾個注意點
1. 對于用戶的角色資訊,springsecurity都是將該資訊存盤在 authorities這個串列之中,并且當我們點進去查看里面存盤的資料型別的時候我們可以發現GrantedAuthority本質上其實是一個字串

之后我們在查看我們添加到 authorities串列中的SimpleGrantedAuthority是什么樣子的

我們查看之后可以發現他的建構式只有一個,并且構造函式的變數就是字串形式的role,并非是我們自己定義的role物件,并且這里有一個注意點就是我們添加的role字串必須要是這樣的形式: ROLE_角色名 否則springsecurity是識別不了角色資訊的.
3. 還有一個就是我們最后的回傳物件,他默認的回傳物件是UserDetails

所以他默認的回傳物件應該是這樣的
return new UserDao(username,userDao.getPassword(),authorities);
回傳一個包含用戶名,用戶名真實密碼,角色集的User物件,但是我這里額外又添加了一個屬性即權限集,是因為我后面可能會用到權限操作,所以我將它一同回傳了,這個屬性不是必須的.
但是如果你有額外回傳的屬性,那么你就需要在User物件定義一個你相應的建構式,就如同我這樣:

- 注意密碼的回傳形式,我們這里是直接回傳的用戶的真實密碼(這里已經加密過了),否則是無法進行身份驗證的環節的.
這樣基本的 身份驗證以及授權操作 就已經完成了
2.4撰寫SpringSecurity的配置類SecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled=true,jsr250Enabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserService userService;
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
// 設定默認的加密方式
return new BCryptPasswordEncoder();
}
@Autowired
public void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
/**
* 靜態資源設定
*/
// @Override
// public void configure(WebSecurity webSecurity) {
// //不攔截靜態資源,所有用戶均可訪問的資源
// webSecurity.ignoring().antMatchers(
// "/",
// "/css/**",
// "/js/**",
// "/images/**",
// "/layui/**"
// );
// }
/**
* http請求設定
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/","/login").permitAll()
.antMatchers("/admin/**").hasRole("admin")
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/swagger-ui.html")
.failureUrl("/login?error")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.permitAll()
.and()
.httpBasic()
.disable()
.csrf()
.disable();
}
}
這里我們主要注意下面這幾個點:
- 我們必須要將 加密規則 注入到spring容器中,否則會報錯,其次就是將加密規則添加到我們的service,這樣在進行身份驗證的時候它才能決議我們已經加密過的密碼,否則他是決議不了的,主要就是這段代碼:
@Bean
public BCryptPasswordEncoder passwordEncoder() {
// 設定默認的加密方式
return new BCryptPasswordEncoder();
}
@Autowired
public void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
- 定義我們的過濾條件
這里主要是在 configure(HttpSecurity http),看到引數是HTTP,我們就知道主要是對HTTP請求進行過濾,認證等操作,首先我們看第一段代碼:
.authorizeRequests()
.antMatchers("/","/login").permitAll()
.antMatchers("/admin/**").hasRole("admin")
.anyRequest().authenticated()
這里我們將登陸頁面定義為全部允許,之后定義/admin下的所有請求都需要擁有admin角色的用戶才能夠訪問,之后就是所有的所有的請求都需要用戶在已經登錄的情況下才能夠進行訪問
每當一段請求規則定義完成之后,如果你想要的重新定義另一段請求規則可以通過and進行隔斷,進行再一次的請求規則撰寫
這里我們看第二段代碼:
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.defaultSuccessUrl("/swagger-ui.html")
.failureUrl("/login?error")
.permitAll()
自定義登錄頁面以及錯誤頁面
第三段代碼:
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.permitAll()
這里我們是定義注銷操作,注銷之后用戶資訊就失效,任何請求都需要重新登錄之后才能完成
3.效果演示
我們先來看看admin用戶的一些操作:

我們可以看到我們訪問swagger的時候是被直接攔截下來的,只有在登錄之后才能訪問,并且因為是admin用戶,所以所有的操作都是可以執行的,之后在我們注銷之后我們再次訪問swagger的時候可以發現請求依舊被攔截下來了,所以注銷功能也是實作了
我們再來看看 游客 的操作:

因為是游客,所以登錄進來之后,這些操作都是不被允許的,可以看到都是報403錯誤,意思就是沒有權限訪問.
原創不易,還希望大家能夠關注一波,點個贊也是好的呢
都看到這兒了,如果覺得對你有幫助的話,可以關注我的公眾號,新人up需要你的幫助!!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/197637.html
標籤:java
