添加依賴
<!-- spring security 權限框架依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Spring Security配置
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
/**
* 授權請求(主要就是靜態界面、下載一些靜態文件)
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**");
}
/**
* 驗證用戶的信息、處理註銷
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
//spring boot監控放行
.antMatchers("/manage/**").permitAll()
.antMatchers("/").permitAll()
// swagger-ui
.antMatchers("/swagger-ui.html", "/webjars/springfox-swagger-ui/**", "/swagger-resources/**",
"/v2/api-docs")
.permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.xhtml")
.loginProcessingUrl("/login")
.successForwardUrl("/index.xhtml")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.permitAll();
}
/**
* 全局的用戶校驗
*/
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
}
看到代碼中我使用的是UserDetailsService,這裏具體談一下UserDetailsService。之前我們採用了配置文件的方式從數據庫中讀取用戶進行登錄。雖然該方式的靈活性相較於靜態賬號密碼的方式靈活了許多,但是將數據庫的結構暴露在明顯的位置上,絕對不是一個明智的做法。本文通過Java代碼實現UserDetailsService接口來實現身份認證。
UserDetailsService在身份認證中的作用
Spring Security中進行身份驗證的是AuthenticationManager接口,ProviderManager是它的一個默認實現,但它並不用來處理身份認證,而是委託給配置好的AuthenticationProvider,每個AuthenticationProvider會輪流檢查身份認證。檢查後或者返回Authentication對象或者拋出異常。
驗證身份就是加載響應的UserDetails,看看是否和用戶輸入的賬號、密碼、權限等信息匹配。此步驟由實現AuthenticationProvider的DaoAuthenticationProvider(它利用UserDetailsService驗證用戶名、密碼和授權)處理。包含 GrantedAuthority 的 UserDetails對象在構建 Authentication對象時填入數據。
上圖解釋:
新建CustomUserService類實現UserDetailsService接口
@Service
public class CustomUserService implements UserDetailsService {
@Autowired
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.getUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用戶名不存在");
}
if (!user.getStatus()) {
throw new UsernameNotFoundException("用戶賬號已被刪除");
}
return new org.springframework.security.core.userdetails.User(username, user.getPassword(), true, true, true,
true, getGrantedAuthorities(user));
}
private List<GrantedAuthority> getGrantedAuthorities(User user) {
List<GrantedAuthority> authorities = new ArrayList<>();
return authorities;
}
}
UserService 添加一個接口實現方法查詢數據庫:
User getUserByUsername(@RequestParam(name = "username") String username);
上述代碼完成,剩下的就是編寫界面代碼了login.html。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head th:include="include/head::head"></head>
<head>
<link th:href="@{/assets/pages/css/login.css}" rel="stylesheet" type="text/css" />
</head>
<body class=" login">
<div class="logo">
</div>
<div class="content">
<form class="login-form" th:action="@{/login}" method="post">
<h3 class="form-title font-green">登 錄</h3>
<div th:if="${param.error}" class="alert alert-danger ">
<button class="close" data-close="alert"></button>
<span >用戶名或密碼錯誤</span>
</div>
<div class="form-group">
<!--ie8, ie9 does not support html5 placeholder, so we just show field title for that-->
<label class="control-label visible-ie8 visible-ie9">用戶名</label>
<input class="form-control form-control-solid placeholder-no-fix" type="text" autocomplete="off" placeholder="用戶名" name="username" />
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">密碼</label>
<input class="form-control form-control-solid placeholder-no-fix" type="password" autocomplete="off" placeholder="密碼" name="password" />
</div>
<div class="form-actions">
<button type="submit" class="btn green uppercase">登 錄</button>
</div>
</form>
</div>
</body>
</html>
最後就是做成功界面了接口,與界面實現了。
@RestController
public class IndexController extends BaseController {
@Autowired
private UserService userService;
@RequestMapping("index.xhtml")
public ModelAndView index(HttpServletRequest request) {
User user = userService.getUserByUsername(getPrincipal());
setSesionAttribute(request, Constants.SESSION_USER, user);
return new ModelAndView("index");
}
private String getPrincipal() {
String userName = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
userName = ((UserDetails) principal).getUsername();
} else {
userName = principal.toString();
}
return userName;
}
}