springsecurity oauth中认证服务器

2020-12-24 10:50:00
admin
原创
84
摘要:springsecurity oauth中认证服务器

springsecurity 认证服务器和资源服务器

springsecurity配置:

项目地址:https://github.com/liujiawan/springSecurity-example


/**
 *  安全配置类
 * @author: GL
 * @program: springSecurity-example
 * @create: 2020年 06月 05日 11:01
 **/
// 包含了 @Configuration 注解
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomUserDetailsService customUserDetailsService;
    /**
     * 认证管理器:
     * 1、认证信息提供方式(用户名、密码、当前用户的资源权限)
     * 2、可采用内存存储方式,也可能采用数据库方式等
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 内存方式存储用户信息
//        auth.inMemoryAuthentication().withUser("admin")
//                .password(passwordEncoder.encode("1234556")).authorities("product");
        // 使用数据库查询的方式
        auth.userDetailsService(customUserDetailsService);
    }

    /**
     * 密码模式需要用到这个认证管理器
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
2、认证服务器设置



/**
 *  安全配置类
 * @author: GL
 * @program: springSecurity-example
 * @create: 2020年 06月 05日 11:01
 **/
// 包含了 @Configuration 注解
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomUserDetailsService customUserDetailsService;
    /**
     * 认证管理器:
     * 1、认证信息提供方式(用户名、密码、当前用户的资源权限)
     * 2、可采用内存存储方式,也可能采用数据库方式等
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 内存方式存储用户信息
//        auth.inMemoryAuthentication().withUser("admin")
//                .password(passwordEncoder.encode("1234556")).authorities("product");
        // 使用数据库查询的方式
        auth.userDetailsService(customUserDetailsService);
    }

    /**
     * 密码模式需要用到这个认证管理器
     * @return
     * @throws Exception
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
3、密码设置:



@Configuration
public class PasswordEncoderBean {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
4、token加强



@Component
public class CustomTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        SysUser user = (SysUser)authentication.getPrincipal();
        final Map<String, Object> additionalInfo = new HashMap<>();
        additionalInfo.put("userId",user.getId());
        additionalInfo.put("userName",user.getNickName());
        ((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(additionalInfo);
        return accessToken;
    }
}
5、token工具



@Configuration
public class TokenConfig {

    /**
     * Redis 管理令牌
     * 添加redis 依赖后, 容器就会有 RedisConnectionFactory 实例
     */
    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    /**
     * jdbc管理token
     * @return
     */
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource dataSource(){
        return new DruidDataSource();
    }

    /**
     * 访问令牌的转换器
     * @return
     */
   @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        // 对称加密进行签名令牌,资源服务器也要采用此密钥来进行解密,来校验令牌合法性
        converter.setSigningKey("abcdefg");
        // 采用非对称加密jwt

        // 第1个参数就是密钥证书文件,第2个参数 密钥口令(-keypass), 私钥进行签名
//        KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
//                new ClassPathResource("oauth2.jks"), "oauth2".toCharArray());
        // 指定非对称加密 oauth2 别名
//        converter.setKeyPair(factory.getKeyPair("oauth2"));
        return converter;
    }

    /**
     * 指定令牌管理方式
     * @return
     */
    @Bean
    public TokenStore tokenStore() {
        // redis 管理令牌
//        return new RedisTokenStore(redisConnectionFactory);
        // 注入数据源
//        return new JdbcTokenStore(dataSource());
        // 使用JWT管理令牌
        return new JwtTokenStore(jwtAccessTokenConverter());
    }
6、userdetail设置



Component("customUserDetailsService")
public class CustomUserDetailsService extends AbstractUserDetailsService {
    Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private SysUserService sysUserService;

    @Override
    SysUser findSysUser(String usernameOrMobile){
        logger.info("请求认证的用户名:" + usernameOrMobile);
        return sysUserService.findByUsername(usernameOrMobile);
    }
7、userdetail 父类设置



public abstract class AbstractUserDetailsService implements UserDetailsService {

    @Autowired
    private SysPermissionService sysPermissionService;

    /**
     * 每次登录都会调用这个方法验证用户信息
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        /**
         * 通过请求的用户名去数据库中查询用户信息,这里用户信息都查询出来了,密码也就获取到了。
         */
        SysUser sysUser = findSysUser(username);

        /**
         * 查询权限
         */
        findSysPermission(sysUser);
        return sysUser;
    }

    /**
     * @param usernameOrMobile 用户或手机号
     * @return
     * @throws UsernameNotFoundException
     */
    abstract SysUser findSysUser(String usernameOrMobile);

    /**
     * 查询认证信息
     * @param sysUser
     * @throws UsernameNotFoundException
     */
    public void findSysPermission(SysUser sysUser) throws UsernameNotFoundException{
        if(sysUser == null) {
            throw new UsernameNotFoundException("未查询到有效用户信息");
        }

        // 2. 查询该用户有哪一些权限
        List<SysPermission> sysPermissions =
                sysPermissionService.findByUserId(sysUser.getId());

        // 无权限
        if(CollectionUtils.isEmpty(sysPermissions)) {
            return;
        }

        // 存入权限,认证通过后用于渲染左侧菜单
        sysUser.setPermissions(sysPermissions);

        // 3. 封装用户信息和权限信息
        List<GrantedAuthority> authorities = new ArrayList<>();
        for(SysPermission sp: sysPermissions) {
            //权限标识
            authorities.add(new SimpleGrantedAuthority(sp.getCode()));
        }
        sysUser.setAuthorities(authorities);
    }
8、资源服务器配置:



@Configuration
@EnableResourceServer // 标识为资源服务器,请求服务中的资源,就要带着token过来,找不到token或token是无效访问不了资源
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级别权限控制
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;

    /**
     * 配置当前资源服务器的ID
     */
    public static final String RESOURCE_ID = "product_api";

    /**
     * 配置当前资源服务器的ID
     * @param resources
     * @throws Exception
     */
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        // 当前资源服务器的资源id,认证服务会认证客户端有没有访问这个资源id的权限,有则可以访问当前服务
        resources.resourceId(RESOURCE_ID)
                // 实现令牌服务, ResourceServerTokenServices实例
//                .tokenServices(tokenService())
                .tokenStore(tokenStore)
        ;
    }

    /**
     * 配置资源服务器如何验证token有效性
     * 1. DefaultTokenServices
     * 如果认证服务器和资源服务器同一服务时,则直接采用此默认服务验证即可
     * 2. RemoteTokenServices (当前采用这个)
     * 当认证服务器和资源服务器不是同一服务时, 要使用此服务去远程认证服务器验证
     * @return
     */
    /*public ResourceServerTokenServices tokenService(){
        // 远程认证服务器进行校验 token 是否有效
        RemoteTokenServices service = new RemoteTokenServices();
        // 请求认证服务器校验的地址,默认情况 这个地址在认证服务器它是拒绝访问,要设置为认证通过可访问
        service.setCheckTokenEndpointUrl("http://localhost:8090/auth/oauth/check_token");
        // 客服端名称
        service.setClientId("sse-pc");
        // 客服端密码
        service.setClientSecret("123456");
        return service;
    }*/

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
                // SpringSecurity不会使用也不会创建HttpSession实例
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                // 授权规则配置
                .antMatchers("/product/*").hasAuthority("sys:user:list")
                // 所有请求,都需要有all范围(scope)
//                .antMatchers("/**").access("#oauth2.hasScope('all')")
        ;
    }


    发表评论
    评论通过审核之后才会显示。
    文章分类
    联系方式
    联系人: 郑州-小万
    电话: 13803993919
    Email: 1027060531@qq.com
    QQ: 1027060531
    网址: www.wanhejia.com