有時我們需要獲取當前登錄的用戶信息(比如用戶名),通常有如下幾種方式來實現。
方法1:通過 Authentication.getPrincipal() 獲取用戶信息
(1)通過 Authentication.getPrincipal() 可以獲取到代表當前用戶的信息,這個對象通常是 UserDetails 的實例。通過 UserDetails 的實例我們可以獲取到當前用戶的用戶名、密碼、角色等信息。
Spring Security 使用一個 Authentication 對象來描述當前用戶的相關信息,而 SecurityContext 持有的是代表當前用戶相關信息的 Authentication 的引用。
這個 Authentication 對象不需要我們自己去創建,在與系統交互的過程中,Spring Security 會自動爲我們創建相應的 Authentication 對象,然後賦值給當前的 SecurityContext。
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
return ((UserDetails) principal).get.getUsername();
}
if (principal instanceof Principal) {
return ((Principal) principal).getName();
}
return "當前登錄用戶:" + String.valueOf(principal);
}
}
(2)由於獲取當前用戶的用戶名是一種比較常見的需求,其實 Spring Security 在 Authentication 中的實現類中已經爲我們做了相關實現,所以獲取當前用戶的用戶名有如下更簡單的方式:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "當前登錄用戶:" + SecurityContextHolder.getContext().getAuthentication().getName();
}
}
方法2:通過注入 Principal 接口獲取用戶信息
在運行過程中,Spring 會將 Username、Password、Authentication、Token 注入到 Principal 接口中,我們可以直接獲取使用:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(Principal principal) {
// 注意:如果未登錄,principal 爲 null
return "當前登錄用戶:" + principal.getName();
}
}
附:獲取登錄用戶的 id 等其他信息
(1)如果我們是基於數據庫的用戶角色配置的話,那麼會創建用戶表對應的實體類,同時用戶實體類需要實現 UserDetails 接口。
關於基於數據庫的用戶角色配置認證更詳細的用法,可以參考我之前顯得文章:
@NoArgsConstructor
@ToString
public class User implements UserDetails {
private Integer id;
private String username;
private String password;
private Boolean enabled;
private Boolean locked;
private List<Role> roles;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return !locked;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return enabled;
}
/** get、set 方法 **/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
(2)我們同樣通過 Authentication.getPrincipal() 可以獲取當前登錄用戶的 UserDetails 實例,然後再轉換成自定義的用戶實體類 User,這樣便能獲取用戶的 ID 等信息:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
User user = (User)principal;
return "當前登錄用戶信息:" + user.toString();
}
}
(3)運行結果如下: