<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
思考:為什麼需要鑑權呢?
系統開發好上線後,API介面會暴露在網際網路上會存在一定的安全風險,例如:爬蟲、惡意存取等。因此,我們需要對非開放API介面進行使用者鑑權,鑑權通過之後再允許呼叫。
spring-boot:2.1.4.RELEASE
spring-security-oauth2:2.3.3.RELEASE(如果要使用原始碼,不要隨意改動這個版本號,因為2.4往上的寫法不一樣了)
mysql:5.7
這邊只用了postman做測試,暫時未使用前端頁面來對接,下個版本角色選單許可權分配的會有頁面的展示
1、存取開放介面http://localhost:7000/open/hello
2、不帶token存取受保護介面http://localhost:7000/admin/user/info
3、登入後獲取token,帶上token存取,成功返回了當前的登入使用者資訊
oauth2一共有四種模式,這邊就不做講解了,網上搜一搜,千篇一律
因為現在只考慮做單方應用的,所以使用的是密碼模式。
後面會出一篇SpringCloud+Oauth2的文章,閘道器鑑權
講一下幾個點吧
1、攔截器設定動態許可權
新建一個 MySecurityFilter類,繼承AbstractSecurityInterceptor,並實現Filter介面
初始化,自定義存取決策管理器
@PostConstruct public void init(){ super.setAuthenticationManager(authenticationManager); super.setAccessDecisionManager(myAccessDecisionManager); }
自定義 過濾器呼叫安全後設資料源
@Override public SecurityMetadataSource obtainSecurityMetadataSource() { return this.mySecurityMetadataSource; }
先來看一下自定義過濾器呼叫安全後設資料源的核心程式碼
以下程式碼是用來獲取到當前請求進來所需要的許可權(角色)
/** * 獲得當前請求所需要的角色 * @param object * @return * @throws IllegalArgumentException */ @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { String requestUrl = ((FilterInvocation) object).getRequestUrl(); if (IS_CHANGE_SECURITY) { loadResourceDefine(); } if (requestUrl.indexOf("?") > -1) { requestUrl = requestUrl.substring(0, requestUrl.indexOf("?")); } UrlPathMatcher matcher = new UrlPathMatcher(); List<Object> list = new ArrayList<>(); //無需許可權的,直接返回 list.add("/oauth/**"); list.add("/open/**"); if(matcher.pathsMatchesUrl(list,requestUrl)) return null; Set<String> roleNames = new HashSet(); for (Resc resc: resources) { String rescUrl = resc.getResc_url(); if (matcher.pathMatchesUrl(rescUrl, requestUrl)) { if(resc.getParent_resc_id() != null && resc.getParent_resc_id().intValue() == 1){ //預設許可權的則只要登入了,無需許可權匹配都可存取 roleNames = new HashSet(); break; } Map map = new HashMap(); map.put("resc_id", resc.getResc_id()); // 獲取能存取該資源的所有許可權(角色) List<RoleRescDTO> roles = roleRescMapper.findAll(map); for (RoleRescDTO rr : roles) roleNames.add(rr.getRole_name()); } } Set<ConfigAttribute> configAttributes = new HashSet(); for(String roleName:roleNames) configAttributes.add(new SecurityConfig(roleName)); log.debug("【所需的許可權(角色)】:" + configAttributes); return configAttributes; }
再來看一下自定義存取決策管理器核心程式碼,這段程式碼主要是判斷當前登入使用者(當前登入使用者所擁有的角色會在最後一項寫到)是否擁有該許可權角色
@Override public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { if(configAttributes == null){ //屬於白名單的,不需要許可權 return; } Iterator<ConfigAttribute> iterator = configAttributes.iterator(); while (iterator.hasNext()){ ConfigAttribute configAttribute = iterator.next(); String needPermission = configAttribute.getAttribute(); for (GrantedAuthority ga: authentication.getAuthorities()) { if(needPermission.equals(ga.getAuthority())){ //有許可權,可存取 return; } } } throw new AccessDeniedException("沒有許可權存取"); }
2、自定義鑑權異常返回通用結果
為什麼需要這個呢,如果不設定這個,對於前端,後端來說都很難去理解鑑權失敗返回的內容,還不能統一解讀,廢話不多說,先看看不設定和設定了的返回情況
(1)未自定義前,沒有攜帶token去存取受保護的API介面時,返回的結果是這樣的
(2)我們規定一下,鑑權失敗的介面返回介面之後,變成下面這種了,是不是更利於我們處理和提示使用者
好了,來看一下是在哪裡去設定的吧
我們資源伺服器OautyResourceConfig,重寫下下面這部分的程式碼,來自定義鑑權異常返回的結果
大夥可以參考下這個https://www.jb51.net/article/131668.htm
@Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.authenticationEntryPoint(authenticationEntryPoint) //token失效或沒攜帶token時 .accessDeniedHandler(requestAccessDeniedHandler); //許可權不足時 }
3、獲取當前登入使用者
第一種:使用JWT攜帶使用者資訊,拿到token後再解析
暫不做解釋
第二種:寫一個SecurityUser實現UserDetails介面(這個工程中使用的是這一種)
原來的只有UserDetails介面只有username和password,這裡我們加上我們系統中的User
protected User user; public SecurityUser(User user) { this.user = user; } public User getUser() { return user; }
在BaseController,每個Controller都會繼承這個的,在裡面寫給getUser()的方法,只要使用者帶了token來存取,我們可以直接獲取當前登入使用者的資訊了
protected User getUser() { try { SecurityUser userDetails = (SecurityUser) SecurityContextHolder.getContext().getAuthentication() .getPrincipal(); User user = userDetails.getUser(); log.debug("【使用者:】:" + user); return user; } catch (Exception e) { } return null; }
那麼使用者登入成功後,如何去拿到使用者的角色集合等呢,這裡面就要實現UserDetailsService介面了
@Service public class TokenUserDetailsService implements UserDetailsService{ @Autowired private LoginService loginService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = loginService.loadUserByUsername(username); //這個我們拎出來處理 if(Objects.isNull(user)) throw new UsernameNotFoundException("使用者名稱不存在"); return new SecurityUser(user); } }
然後在我們的安全設定類中設定UserDetailsService為上面的我們自己寫的就行
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); }
最後我們只需要在loginService裡面實現我們的方法就好,根據我們的實際業務處理判斷該使用者是否存在等
@Override public User loadUserByUsername(String username){ log.debug(username); Map map = new HashMap(); map.put("username",username); map.put("is_deleted",-1); User user = userMapper.findByUsername(map); if(user != null){ map = new HashMap(); map.put("user_id",user.getUser_id()); //查詢使用者的角色 List<UserRoleDTO> userRoles = userRoleMapper.findAll(map); user.setRoles(listRoles(userRoles)); //許可權集合 Collection<? extends GrantedAuthority> authorities = merge(userRoles); user.setAuthorities(authorities); return user; } return null; }
大功告成啦,趕緊動起手來吧!
附上原始碼地址:https://gitee.com/jae_1995/spring-boot-oauth2
資料庫檔案在這
到此這篇關於SpringBoot整合SpringSecurityOauth2實現鑑權-動態許可權的文章就介紹到這了,更多相關SpringBoot整合SpringSecurityOauth2內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45