Spring Boot中整合Spring Security并自定義驗(yàn)證代碼實(shí)例
最終效果
1、實(shí)現(xiàn)頁(yè)面訪問(wèn)權(quán)限限制
2、用戶角色區(qū)分,并按照角色區(qū)分頁(yè)面權(quán)限
3、實(shí)現(xiàn)在數(shù)據(jù)庫(kù)中存儲(chǔ)用戶信息以及角色信息
4、自定義驗(yàn)證代碼
效果如下:
1、免驗(yàn)證頁(yè)面
2、登陸頁(yè)面
在用戶未登錄時(shí),訪問(wèn)任意有權(quán)限要求的頁(yè)面都會(huì)自動(dòng)跳轉(zhuǎn)到登陸頁(yè)面。
3、需登陸才能查看的頁(yè)面
用戶登陸后,可以正常訪問(wèn)頁(yè)面資源,同時(shí)可以正確顯示用戶登錄名:
4、用戶有角色區(qū)分,可以指定部分頁(yè)面只允許有相應(yīng)用戶角色的人使用
4.1、只有ADMIN覺(jué)得用戶才能查看的頁(yè)面(權(quán)限不足)
4.2、只有ADMIN覺(jué)得用戶才能查看的頁(yè)面(權(quán)限滿足)

以下具體說(shuō)明實(shí)現(xiàn)步驟。
代碼實(shí)現(xiàn)
MAVEN引入依賴(lài)
在pom.xml中引入spring security依賴(lài)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
配置Spring Security
在Spring中,配置和使用Spring Security,在不需要修改太多流程細(xì)節(jié)的情況下僅需聲明好攔截規(guī)則,同時(shí)自定義驗(yàn)證過(guò)程中的主要實(shí)現(xiàn)接口(用戶信息UserDetails,用戶信息獲取服務(wù)UserDetailsService,驗(yàn)證工具AuthenticationProvider)即可。其余的流程將由Spring自動(dòng)接管,非常方便。
啟動(dòng)配置
在項(xiàng)目包下添加WebSecurityConfigurerAdapter 的具體實(shí)現(xiàn)類(lèi),實(shí)現(xiàn)Spring Security的啟動(dòng)配置
代碼如下:
@Configurable
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)//允許進(jìn)入頁(yè)面方法前檢驗(yàn)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyAuthenticationProvider provider;//自定義驗(yàn)證
@Autowired
private UserDetailsService userDetailsService;//自定義用戶服務(wù)
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception{
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(StaticParams.PATHREGX.NOAUTH,
StaticParams.PATHREGX.CSS,StaticParams.PATHREGX.JS,StaticParams.PATHREGX.IMG).permitAll()//無(wú)需訪問(wèn)權(quán)限
.antMatchers(StaticParams.PATHREGX.AUTHADMIN).hasAuthority(StaticParams.USERROLE.ROLE_ADMIN)//admin角色訪問(wèn)權(quán)限
.antMatchers(StaticParams.PATHREGX.AUTHUSER).hasAuthority(StaticParams.USERROLE.ROLE_USER)//user角色訪問(wèn)權(quán)限
.anyRequest()//all others request authentication
.authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//將驗(yàn)證過(guò)程交給自定義驗(yàn)證工具
auth.authenticationProvider(provider);
}
URL攔截配置
URL攔截配置可以在上一小節(jié)的WebSecurityConfig 中配置,但是此方法適用于大方向上的配置,具體的特殊路徑也可以在@Controller的注解中具體配置。
如下:
@ResponseBody
@PreAuthorize("hasAuthority('"+StaticParams.USERROLE.ROLE_ADMIN+"')")//這里可以指定特定角色的用戶訪問(wèn)權(quán)限
@RequestMapping(value = "adminrequire", method = RequestMethod.GET)
public String adminrequire(){
return "HELLO from web but you should be admin";
}
用戶、角色表
在本文例子中用戶和角色可以有一對(duì)多的關(guān)系因此可以將用戶和角色分成兩張表。有些例子將用戶和權(quán)限寫(xiě)在同一張表上也是可以的。
/*用戶表*/
@Entity
@Table(name = "user")
public class SystemUser {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String userName;
private String password;
public SystemUser(){}
public SystemUser(SystemUser user){
this.userName = user.getUserName();
this.password = user.getPassword();
this.id = user.getId();
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
/*角色表*/
@Entity
@Table(name = "user_role")
public class UserRole {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String role;
private Long userId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
}
自定義驗(yàn)證
在Spring Boot的Spring Security的教程中默認(rèn)的用戶名、密碼、權(quán)限是在代碼中指定的
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
這顯然是不符合應(yīng)用需求的,所以我們需要提供自定義的AuthenticationProvider,并在上邊代碼中替換即可。在此之前,我們應(yīng)該重寫(xiě)獲取用戶User和權(quán)限的方法。通過(guò)查詢(xún)相關(guān)資料和API,方法提供如下:
自定義UserDetails
UserDetails代表了Spring Security的用戶認(rèn)證實(shí)體,帶有用戶名、密碼、權(quán)限列表、過(guò)期特性等性質(zhì),可以自己聲明類(lèi)實(shí)現(xiàn)UserDetails接口,如果不想自己聲明,也可以用SpringSecurity的默認(rèn)實(shí)現(xiàn)org.springframework.security.core.userdetails.User 本文例子中采用自定義類(lèi):
public class MyUserDetails extends SystemUser implements UserDetails{
private List<UserRole> roles;
public MyUserDetails(SystemUser user, List<UserRole> roles){
super(user);
this.roles = roles;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
if(roles == null || roles.size() <1){
return AuthorityUtils.commaSeparatedStringToAuthorityList("");
}
StringBuilder commaBuilder = new StringBuilder();
for(UserRole role : roles){
commaBuilder.append(role.getRole()).append(",");
}
String authorities = commaBuilder.substring(0,commaBuilder.length()-1);
return AuthorityUtils.commaSeparatedStringToAuthorityList(authorities);
}
@Override
public String getPassword() {
return super.getPassword();
}
@Override
public String getUsername() {
return super.getUserName();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
自定義UserDetailsService
UserDetailsService提供了獲取UserDetails的方式,只要實(shí)現(xiàn)UserDetailsService接口即可,最終生成用戶和權(quán)限共同組成的UserDetails,在這里就可以實(shí)現(xiàn)從自定義的數(shù)據(jù)源中獲取用戶信息了:
@Service("MyUserDetailsImpl")
public class MyUserDetailsService implements UserDetailsService {
@Resource(name = "SystemUserServiceImpl")
private SystemUserService systemUserService;
@Resource(name = "UserRoleServiceImpl")
private UserRoleService userRoleService;
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
SystemUser user;
try {
user = systemUserService.findByName(userName);
} catch (Exception e) {
throw new UsernameNotFoundException("user select fail");
}
if(user == null){
throw new UsernameNotFoundException("no user found");
} else {
try {
List<UserRole> roles = userRoleService.getRoleByUser(user);
return new MyUserDetails(user, roles);
} catch (Exception e) {
throw new UsernameNotFoundException("user role select fail");
}
}
}
}
自定義AuthenticationProvider
AuthenticationProvider 提供用戶UserDetails的具體驗(yàn)證方式,在這里可以自定義用戶密碼的加密、驗(yàn)證方式等等。因?yàn)椴┪闹饕v的是如何引入Spring Security和如何自定義驗(yàn)證代碼,所以這里為了簡(jiǎn)便,我直接采用明文比較方式:
@Component
public class MyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private MyUserDetailsService userService;
/**
* 自定義驗(yàn)證方式
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = (String) authentication.getCredentials();
MyUserDetails user = (MyUserDetails) userService.loadUserByUsername(username);
if(user == null){
throw new BadCredentialsException("Username not found.");
}
//加密過(guò)程在這里體現(xiàn)
if (!password.equals(user.getPassword())) {
throw new BadCredentialsException("Wrong password.");
}
Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}
@Override
public boolean supports(Class<?> arg0) {
return true;
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
java(包括springboot)讀取resources下文件方式實(shí)現(xiàn)
這篇文章主要介紹了java(包括springboot)讀取resources下文件方式實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
springboot項(xiàng)目之相互依賴(lài)報(bào)錯(cuò)問(wèn)題(基于idea)
這篇文章主要介紹了springboot項(xiàng)目之相互依賴(lài)報(bào)錯(cuò)問(wèn)題(基于idea),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
IDEA 啟動(dòng) Tomcat 項(xiàng)目輸出亂碼的解決方法
這篇文章主要介紹了IDEA 啟動(dòng) Tomcat 項(xiàng)目輸出亂碼的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
Servlet編程第一步之從零構(gòu)建Hello?World應(yīng)用詳細(xì)步驟+圖解
本文詳細(xì)介紹了Servlet和maven的基本概念及其在JavaWeb開(kāi)發(fā)中的應(yīng)用,首先解釋了Servlet是一個(gè)在服務(wù)器上處理請(qǐng)求的Java程序,然后介紹了maven作為管理和構(gòu)建Java項(xiàng)目的工具,需要的朋友可以參考下2024-10-10
Spring IOC創(chuàng)建對(duì)象的兩種方式
這篇文章主要給大家介紹了關(guān)于Spring IOC創(chuàng)建對(duì)象的兩種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
關(guān)于Java異常處理的幾條建議_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
Java提供了拋出異常、捕捉異常和finally語(yǔ)句的使用來(lái)處理程序異常,下面就來(lái)具體看一下關(guān)于Java異常處理的幾條建議2017-06-06

