使用SpringSecurity設(shè)置角色和權(quán)限的注意點(diǎn)
SpringSecurity設(shè)置角色和權(quán)限
概念
在UserDetailsService的loadUserByUsername方法里去構(gòu)建當(dāng)前登陸的用戶時(shí),你可以選擇兩種授權(quán)方法,即角色授權(quán)和權(quán)限授權(quán),對(duì)應(yīng)使用的代碼是hasRole和hasAuthority,而這兩種方式在設(shè)置時(shí)也有不同,下面介紹一下:
- 角色授權(quán):授權(quán)代碼需要加ROLE_前綴,controller上使用時(shí)不要加前綴
- 權(quán)限授權(quán):設(shè)置和使用時(shí),名稱保持一至即可
使用mock代碼
@Component public class MyUserDetailService implements UserDetailsService { ? @Autowired ? private PasswordEncoder passwordEncoder; ? @Override ? public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException { ? ? User user = new User(name, ? ? ? ? passwordEncoder.encode("123456"), ? ? ? ? AuthorityUtils.commaSeparatedStringToAuthorityList("read,ROLE_USER"));//設(shè)置權(quán)限和角色 ? ? // 1. commaSeparatedStringToAuthorityList放入角色時(shí)需要加前綴ROLE_,而在controller使用時(shí)不需要加ROLE_前綴 ? ? // 2. 放入的是權(quán)限時(shí),不能加ROLE_前綴,hasAuthority與放入的權(quán)限名稱對(duì)應(yīng)即可 ? ? return user; ? } }
上面使用了兩種授權(quán)方法,大家可以參考。
在controller中為方法添加權(quán)限控制
?@GetMapping("/write") ? @PreAuthorize("hasAuthority('write')") ? public String getWrite() { ? ? return "have a write authority"; ? } ? @GetMapping("/read") ? @PreAuthorize("hasAuthority('read')") ? public String readDate() { ? ? return "have a read authority"; ? } ? @GetMapping("/read-or-write") ? @PreAuthorize("hasAnyAuthority('read','write')") ? public String readWriteDate() { ? ? return "have a read or write authority"; ? } ? @GetMapping("/admin-role") ? @PreAuthorize("hasRole('admin')") ? public String readAdmin() { ? ? return "have a admin role"; ? } ? @GetMapping("/user-role") ? @PreAuthorize("hasRole('USER')") ? public String readUser() { ? ? return "have a user role"; ? }
網(wǎng)上很多關(guān)于hasRole和hasAuthority的文章,很多都說(shuō)二者沒(méi)有區(qū)別,但我認(rèn)為,這是spring設(shè)計(jì)者的考慮,兩種性質(zhì)完成獨(dú)立的東西,不存在任何關(guān)系,一個(gè)是用做角色控制,一個(gè)是操作權(quán)限的控制,二者也并不矛盾。
Security角色和權(quán)限的概念
Security中一些可選的表達(dá)式
permitAll
永遠(yuǎn)返回truedenyAll
永遠(yuǎn)返回falseanonymous
當(dāng)前用戶是anonymous時(shí)返回truerememberMe
當(dāng)前用戶是rememberMe用戶時(shí)返回trueauthenticated
當(dāng)前用戶不是anonymous時(shí)返回truefullAuthenticated
當(dāng)前用戶既不是anonymous也不是rememberMe用戶時(shí)返回truehasRole(role)
用戶擁有指定的角色權(quán)限時(shí)返回truehasAnyRole([role1,role2])
用戶擁有任意一個(gè)指定的角色權(quán)限時(shí)返回truehasAuthority(authority)
用戶擁有指定的權(quán)限時(shí)返回truehasAnyAuthority([authority1,authority2])
用戶擁有任意一個(gè)指定的權(quán)限時(shí)返回truehasIpAddress('192.168.1.0')
請(qǐng)求發(fā)送的Ip匹配時(shí)返回true
看到上述的表達(dá)式,應(yīng)該能發(fā)現(xiàn)一些問(wèn)題,在Security中,似乎并沒(méi)有嚴(yán)格區(qū)分角色和權(quán)限,
如果沒(méi)有角色和權(quán)限的區(qū)別,只需要hasRole()函數(shù)就夠了, hasAuthority()是做什么用的?
答:區(qū)別就是,hasRole()的權(quán)限名稱需要用 "ROLE_" 開頭,而hasAuthority()不需要,而且,這就是全部的區(qū)別。
在通常的系統(tǒng)設(shè)計(jì)中,我們區(qū)分角色和權(quán)限,但是,判斷 “用戶是不是管理員”,和判斷 “是否擁有管理員權(quán)限”,在代碼邏輯上,其實(shí)是完全一致的,角色是一種權(quán)限的象征,可以看做是權(quán)限的一種。因此,不區(qū)分角色和權(quán)限,本身就是合理的做法。
如果撇開別的問(wèn)題不談,只考慮權(quán)限的問(wèn)題,我們可以將角色視為權(quán)限的一種,但是,角色是用戶的固有屬性,在用戶管理上還是非常有必要的,在Security4中,處理“角色”(如RoleVoter、hasRole表達(dá)式等)的代碼總是會(huì)添加ROLE_前綴,它更加方便開發(fā)者從兩個(gè)不同的維度去設(shè)計(jì)權(quán)限。
Spring Security3 到 Spring Security4 的遷移文檔:
S.O. (Stack Overflow)網(wǎng)站對(duì)這個(gè)問(wèn)題的描述:
Think of a GrantedAuthority as being a "permission" or a "right". Those "permissions" are (normally) expressed as strings (with the getAuthority() method). Those strings let you identify the permissions and let your voters decide if they grant access to something.
You can grant different GrantedAuthoritys (permissions) to users by putting them into the security context. You normally do that by implementing your own UserDetailsService that returns a UserDetails implementation that returns the needed GrantedAuthorities.
Roles (as they are used in many examples) are just "permissions" with a naming convention that says that a role is a GrantedAuthority that starts with the prefix ROLE_. There's nothing more. A role is just a GrantedAuthority - a "permission" - a "right". You see a lot of places in spring security where the role with its ROLE_ prefix is handled specially as e.g. in the RoleVoter, where the ROLE_ prefix is used as a default. This allows you to provide the role names withtout the ROLE_ prefix. Prior to Spring security 4, this special handling of "roles" has not been followed very consistently and authorities and roles were often treated the same (as you e.g. can see in the implementation of the hasAuthority() method in SecurityExpressionRoot - which simply calls hasRole()). With Spring Security 4, the treatment of roles is more consistent and code that deals with "roles" (like the RoleVoter, the hasRole expression etc.) always adds the ROLE_ prefix for you. So hasAuthority('ROLE_ADMIN') means the the same as hasRole('ADMIN') because the ROLE_ prefix gets added automatically. See the spring security 3 to 4 migration guide for futher information.
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
從java源碼分析線程池(池化技術(shù))的實(shí)現(xiàn)原理
這篇文章主要介紹了從java源碼分析線程池(池化技術(shù))的實(shí)現(xiàn)原理,池化技術(shù)是一種編程技巧,當(dāng)程序出現(xiàn)高并發(fā)時(shí),能夠明顯的優(yōu)化程序,降低系統(tǒng)頻繁創(chuàng)建銷毀連接等額外開銷,下文更多的相關(guān)介紹需要的小伙伴可以參考一下2022-04-04Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說(shuō)明
這篇文章主要介紹了Java中forEach使用lambda表達(dá)式,數(shù)組和集合的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Eclipse+Java+Swing實(shí)現(xiàn)斗地主游戲(代碼)
這篇文章主要介紹了Eclipse+Java+Swing實(shí)現(xiàn)斗地主游戲并附上詳細(xì)的代碼實(shí)現(xiàn),正在學(xué)習(xí)的你可以當(dāng)小練習(xí)練練,希望對(duì)你有所幫助2022-01-01Spring Boot使用Servlet及Filter過(guò)程詳解
這篇文章主要介紹了Spring Boot使用Servlet及Filter過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07基于JavaMail的Java實(shí)現(xiàn)復(fù)雜郵件發(fā)送功能
這篇文章主要為大家詳細(xì)介紹了基于JavaMail的Java實(shí)現(xiàn)復(fù)雜郵件發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09SpringBoot項(xiàng)目創(chuàng)建使用+配置文件+日志文件詳解
Spring的出現(xiàn)是為了簡(jiǎn)化 Java 程序開發(fā),而 SpringBoot 的出現(xiàn)是為了簡(jiǎn)化 Spring 程序開發(fā),這篇文章主要介紹了SpringBoot項(xiàng)目創(chuàng)建使用+配置文件+日志文件,需要的朋友可以參考下2023-02-02SPRING FRAMEWORK BEAN作用域和生命周期原理解析
這篇文章主要介紹了SPRING FRAMEWORK BEAN作用域和生命周期原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-01-01