栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springsecurity-oauth2之认证服务器的编写(二)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springsecurity-oauth2之认证服务器的编写(二)

springsecurity-oauth2之认证服务器的编写(二)

这里忽略springcloud-alibaba的搭建,只讲springsecurity的部分。
把生成的密钥对文件放在resources目录下
认证服务器的代码结构图

1.导包

引入spring-security和oauth2的必须包


            org.springframework.cloud
            spring-cloud-starter-security
        
        
        
            org.springframework.cloud
            spring-cloud-starter-oauth2
        
        
        
            org.springframework.security
            spring-security-oauth2-jose
        
2.配置yml

严格来说不需要特别配置,这里只讲两个:
①表示后发现的bean会覆盖之前相同名称的bean

spring:
   main:
     allow-bean-definition-overriding: true

②配置客户端的clientId、clientSecret(非必须),表示这个客户端的标识,资源服务器会根据这个标识去oauth_client_details找其可访问的资源(即resource_ids字段以及scope字段),实际开发中登录时可有哭护短传来。

auth:
  clientId: c1
  clientSecret: secret1
3.配置类AuthServerConfig
@Configuration
@EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
    //对称密钥------改用非对称密钥
    //private static final String SIGNING_KEY = "oauth";
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private AuthorizationCodeServices authorizationCodeServices;
    @Resource
    private JwtAccessTokenConverter accessTokenConverter;
    @Resource
    private TokenStore tokenStore;
    @Resource
    private ClientDetailsService clientDetailsService;

    
    @Bean
    public ClientDetailsService clientDetailsService(DataSource dataSource) {
        JdbcClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);
        ((JdbcClientDetailsService) clientDetailsService).setPasswordEncoder(passwordEncoder);
        return clientDetailsService;
    }

    
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService);
    }

    //配置令牌访问端点
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)//认证管理(密码模式需要)
                .authorizationCodeServices(authorizationCodeServices)//授权码服务
                .tokenServices(tokenServices())//令牌管理服务
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);//允许post提交访问令牌
    }

    
    @Bean
    public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {
        return new JdbcAuthorizationCodeServices(dataSource);
    }

    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setClientDetailsService(clientDetailsService);//客户端详情
        tokenServices.setSupportRefreshToken(true);//支持刷新令牌
        tokenServices.setTokenStore(tokenStore);//令牌存储策略
        //令牌增强  使用jwt令牌
        //使用jwt令牌来替代默认令牌,这样做的好处是携带默认令牌访问资源,每次都要通过授权服务来认证令牌是否有效,
        // 而jwt则可以做到资源服务中自己解析从而判断令牌的有效性;另外一个优势就是jwt令牌有更高的安全性,
        // 可以使用公钥和私钥进行加密和解密,不容易被破解。
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(accessTokenConverter));
        tokenServices.setTokenEnhancer(tokenEnhancerChain);

        tokenServices.setAccessTokenValiditySeconds(7200);//令牌默认有效期2小时
        tokenServices.setRefreshTokenValiditySeconds(9600);//刷新令牌默认有效期
        return tokenServices;
    }
    
    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        //加载密钥
        converter.setKeyPair(keyPair());
        return converter;
    }
    
    @Bean
    public KeyPair keyPair(){
        KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource("macrosoft.jks"),"420188".toCharArray());
        KeyPair keyPair = factory.getKeyPair("macrosoft", "420188".toCharArray());
       return keyPair;
    }
    
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.tokenKeyAccess("permitAll()")//oauth/token_key是公开
                .checkTokenAccess("permitAll()") //oauth/check_token   已经验证了的客户端才能请求check_token 端点
                .allowFormAuthenticationForClients();//表单认证(申请令牌)
    }
}
4.配置类SecurityConfig
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()//跨域伪造请求无效
                .authorizeRequests().antMatchers("
    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailServiceImpl();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }
    
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(HttpMethod.GET,
                "/favicon.ico",
                "*.css",
                "*.js");
    }
    
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}
5.自定义数据库操作UserDetailServiceImpl
public class UserDetailServiceImpl implements UserDetailsService {

    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysRoleMapper sysRoleMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserDetails userDetails = null;
        try {
        	//根据username查询用户信息
            List sysUserList = sysUserMapper.selectByUserNameSysUsers(username);
            if (CollectionUtils.isEmpty(sysUserList)) {
                throw new UsernameNotFoundException("该用户不存在!");
            }
            SysUserEntity sysUserEntity = sysUserList.get(0);
            //根据userId查询角色权限
            String roles = sysRoleMapper.getRoleNameById(sysUserEntity.getId());
            List authorities = new ArrayList<>();
            String[] arrstr = roles.split(";");
            if (ObjectUtils.isNotEmpty(arrstr)) {
                for (String role : arrstr) {
                    authorities.add(new SimpleGrantedAuthority(role));
                }
            }
            userDetails =
                    new User(username
                            , sysUserEntity.getPassword()
                            , true
                            , true
                            , true
                            , true
                            , authorities);

        } catch (UsernameNotFoundException e) {
            e.printStackTrace();
        }
        return userDetails;
    }
}
6.到这里认证的配置就配完了,这里在放一段登录的代码(service)
 @Override
    public RespResult login(LoginRequestDTO loginRequestDTO) {

        RespResult result = new RespResult<>();

        ServiceTemplate.executeApiService(getClass(),
                AuthScenceEnum.AUTH_LOGIN_SCENCE,
                loginRequestDTO,
                result,
                request -> {
                    String username = loginRequestDTO.getUsername();
                    String password = loginRequestDTO.getPassword();
                    //1.获取当前服务路径
                    ServiceInstance serviceInstance = loadBalancerClient.choose("macro-auth");
                    URI uri = serviceInstance.getUri();
                    String url = uri + "/auth/oauth/token";
                    //2.组装请求体参数
                    MultiValueMap body = new linkedMultiValueMap<>();
                    body.add("grant_type", "password");
                    body.add("username", username);
                    body.add("password", password);
                    //3.在请求头组装clientId和clientSecret
                    MultiValueMap headers = new linkedMultiValueMap<>();
                    //注意:重点,客户端在登录时可以传入clientId、clientSecret(线下给到客户端),那么这样就可以在oauth_client_details配置该clientId的访问资源服务器了
                    //这里目前写死只有一个clientId、clientSecret(即c1和secret1),在oauth_client_details表中配置了c1对应的resource_ids字段的res1,res2,res3
                    //也就是说资源服务器标识为res1或res2或res3的,clientId为c1的皆可访问
                    headers.add("Authorization", getHttpBasic(clientId, clientSecret));
                    //4.组装最终请求参数
                    HttpEntity> requestEntity = new HttpEntity<>(body, headers);
                    //5.发起登录请求接口
                    ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, Map.class);
                    //6.获取返回数据
                    Map map = responseEntity.getBody();
                    boolean flag = (map == null || map.get("access_token") == null || map.get("refresh_token") == null || map.get("jti") == null);
                    AssertUtil.assertFalse(flag, AuthErrorEnum.GET_ACCESS_TOKEN_FAIL);
                    //7.封装返回数据
                    LoginResultDTO loginResultDTO = new LoginResultDTO();
                    loginResultDTO.setAccessToken((String) map.get("access_token"));
                    loginResultDTO.setRefreshToken((String) map.get("refresh_token"));
                    loginResultDTO.setJti((String) map.get("jti"));
                    //8.数据存入redis
                    redisService.setCachevalueForTimes(RedisKeyTemplate.redisUseUserNameAsKey(username), JSON.toJSONString(loginResultDTO),600, TimeUnit.SECONDS);
                    result.setData(loginResultDTO);
                });
        return result;
    }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/781536.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号