spring-boot: 2.1.4.RELEASE
spring-security-oauth3: 2.3.3.RELEASE (ソースコードを使用する場合は、これを変更しないでください)バージョン番号は任意、2.4以降は書き方が違うので)
mysql: 5.7
ここではテストにpostmanのみを使用しており、フロントは終了ページはまだドッキングに使用されていません。次に、バージョン ロール メニューの権限割り当てのページが表示されます。メニュー
1。オープン インターフェイス http://localhost:7000/open/hello ## にアクセスします。
#2 . トークンなしで、保護されたインターフェイス http://localhost:7000/admin/user/info # にアクセスします。 3. ログイン後にトークンを取得し、トークンを持ってアクセスし、正常に戻る 現在のログインユーザー情報 realizeoauth3 には合計 4 つのモードがありますが、ここでは説明しません。はい、オンラインで検索したところ、同じことが見つかりました。ここでは一方的なアプリケーションのみを考慮しているため、パスワード モードを使用します。 SpringCloud Oauth3、ゲートウェイ認証については後ほど記事で紹介しますいくつかのポイントについて話しましょう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("没有权限访问"); }
@Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.authenticationEntryPoint(authenticationEntryPoint) //token失效或没携带token时 .accessDeniedHandler(requestAccessDeniedHandler); //权限不足时 }
#3. 現在のログイン ユーザーを取得します
##最初の方法: JWT を使用してユーザー情報を伝え、トークンを取得した後に解析します##今のところ説明はありません
2 番目の方法: UserDetails インターフェイスを実装する SecurityUser を作成します (これがこのプロジェクトで使用されます)
元の唯一の UserDetails インターフェイスにはユーザー名とパスワードしかありません。ここでシステムにユーザーを追加します。
protected User user; public SecurityUser(User user) { this.user = user; } public User getUser() { return user; }
BaseControllerでは、各Controllerがこれを継承してgetUser()メソッドを記述し、ユーザーがトークンを持ってアクセスすれば、現在ログインしているユーザーの情報を直接取得することができます。
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); } }
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); }
@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; }
以上がSpringBoot は SpringSecurityOauth2 をどのように統合して、認証のための動的な権限の問題を実装しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。