Spring Security Oauth2自定义登录简单实现

 参考文章Spring Security Oauth2关于自定义登录的几种解决方案(一)_小丑竟是我自己-CSDN博客

初衷

由于oauth2默认提供的password模式需要client_id,秘钥,grant_type,用户名,密码这几个参数才可以进行登录验证。

有没有一种方式,只输入用户名,密码就能登录的呢?

代码实现

目录

初衷

代码实现

新建用户名密码权限认证类

新建oauth核心配置类

新建登录方法

配置客户端

测试

总结


导入oauth包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.itcv.spring.oauth.demo</groupId>
	<artifactId>spring-oauth-demo</artifactId>
	<version>1.0-SNAPSHOT</version>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.10.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

<dependencies>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-actuator</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-freemarker</artifactId>
		<version>2.3.12.RELEASE</version>
	</dependency>

	<!-- OAuth2 认证服务器-->
	<!-- spring oauth2.0 (包含了spring security无需单独引入) 相关 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-oauth2</artifactId>
		<version>2.2.0.RELEASE</version>
		<exclusions>
			<!--旧版本 redis操作有问题-->
			<exclusion>
				<artifactId>spring-security-oauth2</artifactId>
				<groupId>org.springframework.security.oauth</groupId>
			</exclusion>
		</exclusions>
	</dependency>
	<dependency>
		<groupId>org.springframework.security.oauth</groupId>
		<artifactId>spring-security-oauth2</artifactId>
		<version>2.3.8.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>com.alibaba</groupId>
		<artifactId>fastjson</artifactId>
		<version>1.2.78</version>
	</dependency>
	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
	</dependency>
</dependencies>
</project>

 

新建用户名密码权限认证类

@Component
public class AdminPwdAuthenticationProvider implements AuthenticationProvider {
​
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private UserDetailsService userDetailsService;
​
    //认证方法
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePasswordAuthenticationToken adminLoginToken = (UsernamePasswordAuthenticationToken) authentication;
        System.out.println("===进入Admin密码登录验证环节====="+ JSON.toJSONString(adminLoginToken));
        UserDetails userDetails = userDetailsService.loadUserByUsername(adminLoginToken.getName());
        //matches方法,前面为明文,后续为加密后密文
        //匹配密码。进行密码校验
        if(passwordEncoder.matches(authentication.getCredentials().toString(),userDetails.getPassword())){
            return  new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
        }
        throw  new BadCredentialsException("用户名密码不正确");
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }
}

新建oauth核心配置类

@Configuration
@EnableWebSecurity
@EnableAuthorizationServer //这个配置是必须加的,不加的话,接下来使用TokenEndpoint会提示找不到对应的类
public class SecurityConfig extends WebSecurityConfigurerAdapter {
​
    private static final String[] excludedAuthPages = {"/login/**",};
    @Override
    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
​
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
​
    @Bean
    @Override
    //模拟用户
    public UserDetailsService userDetailsService() {
        // 测试方便采用内存存取方式
        InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager();
        userDetailsService.createUser(User.withUsername("user_1").password(passwordEncoder().encode("123456")).authorities("ROLE_USER").build());
        userDetailsService.createUser(User.withUsername("user_2").password(passwordEncoder().encode("1234567")).authorities("ROLE_USER").build());
        return userDetailsService;
    }
​
​
    @Autowired
    private AdminPwdAuthenticationProvider adminPwdAuthenticationProvider;
​
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //此处注入一个默认的service,也可以不注入,我做测试时使用,根据需求,该service非admin-userservice
        auth.userDetailsService(userDetailsService());
        //添加两个Provider
       // auth.authenticationProvider(adminSmsAuthenticationProvider);
        auth.authenticationProvider(adminPwdAuthenticationProvider);
    }
​
    //安全拦截机制(最重要)
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().contentTypeOptions().disable()
                .frameOptions().sameOrigin()
                .and()
                .authorizeRequests()
                .antMatchers(excludedAuthPages).permitAll()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
                .and().authorizeRequests()
                .anyRequest().authenticated()
                .and().formLogin().disable()
                .exceptionHandling()
                .and().csrf().disable()
                .logout().disable().authorizeRequests();
    }
}

新建登录方法

@RestController
@RequestMapping("/")
public class LoginController {
​
    @Autowired
    private OAuth2ClientProperties oauth2ClientProperties;
    @Autowired
    private TokenEndpoint tokenEndpoint;
​
    @PostMapping("/login/admin")
    public OAuth2AccessToken adminLogin(@RequestBody UserRequest request) throws HttpRequestMethodNotSupportedException {
        //创建客户端信息,客户端信息可以写死进行处理,因为Oauth2密码模式,客户端双信息必须存在,所以伪装一个
        //如果不想这么用,需要重写比较多的代码
        User  clientUser= new User(oauth2ClientProperties.getClientId(),oauth2ClientProperties.getClientSecret(), new ArrayList<>());
        //生成已经认证的client
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(clientUser,null, new ArrayList<>());
        Map<String, String> parameters = new HashMap<String, String>();
        //封装成一个UserPassword方式的参数体,放入手机号
        parameters.put("username", request.getPhone());
        //放入验证码
        parameters.put("password", request.getVcode());
        //授权模式为:密码模式
        parameters.put("grant_type", "password");
        //调用自带的获取token方法。
        OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(token, parameters).getBody();
        return oAuth2AccessToken;
    }

配置客户端

security:
  oauth2:
    client:
      clientId: demoApp
      clientSecret: 123456
      scope: ALL
      authorized-grant-types: password,refresh_token

测试

访问自定义登录接口,输入用户名,密码可以正常登录

 

访问oauth2自带登录接口

 

 

总结

违背了初衷,原本想着是两个都可以正常使用的;oauth2自带的登录接口也走到了自定义的类里边。

源码地址

spring-security-demo: spring-sevurity入门实例

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值