zoukankan      html  css  js  c++  java
  • Spring Cloud微服务安全实战_4-6_OAuth2的Scope参数_token转换为用户信息

    一、通过OAuth2 Toke的Scope参数控制权限

    1,在服务端认证服务器里,通过配置客户端的Scope,可以控制给这个客户端生成的token有哪些权限

     2,在客户端,申请令牌的时候,可以指定scope

    示例:在资源服务器 (nb-order-api)里,控制post请求的token ,其scope必须包含write权限,get请求的token必须包含read权限。

    用postman客户端(clientId=orderApp)去认证服务器申请一个scpoe=read的token,去调用资源服务器里的Post请求:

     调用这个创建订单的Post请求:

     返回错误信息:

     二,将token转换为用户信息

    目前在资源服务器里,想要获取用户信息,在Controller里,可以通过 @AuthenticationPrincipal 注解,获取生成token的用户名。但是获取不到用户的其他信息,如userId等。

    做如下修改:

    1,在资源服务器的安全配置: OAuth2WebSecurityConfig 里,的  tokenServices方法里,配置一个 AccessTokenConverter,用来将token信息转换为 User 信息

    2,新建UserDetailsService的实现类

    OAuth2WebSecurityConfig:
    package com.nb.security.resource.server;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.authentication.AuthenticationManager;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationManager;
    import org.springframework.security.oauth2.provider.token.*;
    
    /**
     * 怎么验发往本服务的请求头的令牌
     * 1,自定义tokenServices ,说明去哪里去验token
     * 2,重写authenticationManagerBean()方法,将AuthenticationManager暴露为一个Bean
     *    要认证跟用户相关的信息,一般用 AuthenticationManager
     *
     * 这样配置了后,所有发往nb-order-api的请求,
     * 需要验token的时候就会发请求去http://localhost:9090/oauth/check_token验token,获取到token对应的用户信息
     */
    @Configuration
    @EnableWebSecurity
    public class OAuth2WebSecurityConfig extends WebSecurityConfigurerAdapter{
    
        @Autowired
        private UserDetailsService userDetailsService;
    
        /**
         * 通过这个Bean,去远程调用认证服务器,验token
         * @return
         */
        @Bean
        public ResourceServerTokenServices tokenServices(){
            RemoteTokenServices tokenServices = new RemoteTokenServices();
            tokenServices.setClientId("orderService");//在认证服务器配置的,订单服务的clientId
            tokenServices.setClientSecret("123456");//在认证服务器配置的,订单服务的ClientSecret
            tokenServices.setCheckTokenEndpointUrl("http://localhost:9090/oauth/check_token");
            //配置一个转换器,将token信息转换为用户对象
            // TODO:获取用户信息本应该是认证服务器的事吧!总感觉在这里做不合适
            tokenServices.setAccessTokenConverter(getAccessTokenConverter());
            return tokenServices;
        }
    
        //转换器,将token转换为用户信息
        private AccessTokenConverter getAccessTokenConverter() {
            DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
            //这个类的目的是设UserDetailsService,来将token转换为用户信息,不设默认为空
            DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter();
            userTokenConverter.setUserDetailsService(userDetailsService);
            accessTokenConverter.setUserTokenConverter(userTokenConverter);
            return accessTokenConverter;
        }
    
        /**
         * 要认证跟用户相关的信息,一般用 AuthenticationManager
         * 覆盖这个方法,可以将AuthenticationManager暴露为一个Bean
         *
         * @return
         * @throws Exception
         */
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            OAuth2AuthenticationManager authenticationManager = new OAuth2AuthenticationManager();
            authenticationManager.setTokenServices(tokenServices());//设置为自定义的TokenServices,去校验令牌
            return authenticationManager;
        }
    
    }
    UserDetailsServiceImpl
    package com.nb.security.resource.server;
    
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.stereotype.Component;
    
    @Component("userDetailsService") //TODO:不
    public class UserDetailsServiceImpl implements UserDetailsService {
    
    
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            //这里就不去读数据库了
            User user = new User();
            user.setId(1L);
            user.setUsername(username);
            return user;
        }
    }

    User对象,实现UserDetails接口:

    package com.nb.security.resource.server;
    
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.AuthorityUtils;
    import org.springframework.security.core.userdetails.UserDetails;
    
    import java.util.Collection;
    
    public class User implements UserDetails{
    
        private Long id;
    
        private String username;
    
        private String password;
    
    
        @Override
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_ADMIN");
        }
    
    
        @Override
        public boolean isAccountNonExpired() {
            return true;  //账号没过期
        }
    
        @Override
        public boolean isAccountNonLocked() {
            return true;//账号没被锁定
        }
    
        @Override
        public boolean isCredentialsNonExpired() {
            return true;//密码没过期
        }
    
        @Override
        public boolean isEnabled() {
            return true;//是否可用
        }
    
    
        @Override
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        @Override
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
    
    
    }

    然后在订单Controller里,就可以取到用户的 id等其他属性了:

    用 @AuthenticationPrincipal User user 注解可以取出User对象。

    用 @AuthenticationPrincipal(expression = "#this.id") Long id  可以取出User里面的属性

     代码放在了github :https://github.com/lhy1234/springcloud-security/tree/chapt-4-6-config-persistence

    下一节,说将token持久化到数据库
  • 相关阅读:
    图片优化工具
    Mac显示和隐藏文件的命令
    C中调用LUA回调(LUA注册表)
    电信猫拨号再加路由器
    VMware NAT模式网络配置
    spring mvc 数据绑定
    银行存款余额调节表实例
    加强银行余额调节表在财务管理中的作用
    c语言typedef的用法-解惑阿!很多天书般的东西解释的不错(转)
    c语言指针详解(转载)
  • 原文地址:https://www.cnblogs.com/lihaoyang/p/12057588.html
Copyright © 2011-2022 走看看