java - 创建自定义 OAuth 登录页面和自定义 jwt 令牌
问题描述
我使用默认的 Spring Boot 配置创建了一个 OAuth 授权服务器,其中客户端被重定向到自动生成的登录页面,userDetailsService 查找 User 表并进行身份验证,并且在成功身份验证后服务器返回一个 jwt 令牌。现在我想定制这个并改变两件事,但我很难做到。
1)使用我自己的 login.jsp 页面而不是自动生成的登录页面,这样我就可以有一个额外的字段(例如下拉列表)并将其与用户名和密码一起用于身份验证,因为我有不同的用户表
2)我没有使用默认的UserDetailsService,而是尝试实现自己的AuthenticationProvider,这是因为我有多个用户表,并且希望根据额外字段中的值在正确的表中搜索用户(1中提到的下拉列表) . 另外如何获取 AuthenticationProvider 中的下拉列表值?
在我的属性文件中,我设置了: spring.mvc.view.prefix: /WEB-INF/jsp/ 和 spring.mvc.view.suffix: .jsp
@Configuration
@EnableWebSecurity
public class ServerWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new DefaultAuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
}
@Configuration
@EnableAuthorizationServer
@Import(ServerWebSecurityConfig.class)
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).accessTokenConverter(accessTokenConverter()).authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("permitAll()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
clients.withClientDetails(jdbcClientDetailsService);
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("secret");
return converter;
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Bean
public PasswordEncoder userPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
public class DefaultAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication.getName() == null || authentication.getCredentials() == null
|| authentication.getName().isEmpty() || authentication.getCredentials().toString().isEmpty()) {
return null;
}
final String userName = authentication.getName();
final String password = (String) authentication.getCredentials();
// final String userTable = how to get this?
// make db query in correct table based on value of userTable
User user = null;
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
for (UserAuthority authority : user.getUserAuthorities()) {
authorities.add(new CustomGrantedAuthority(authority.getAuthority().getName()));
}
Map<String, String> userDetails = new HashMap<>();
userDetails.put("username", userName);
return new UsernamePasswordAuthenticationToken(userDetails, password, authorities);
}
@Override
public boolean supports(Class<?> authentication) {
return false;
}
}
@Controller
public class OAuthController {
@RequestMapping("/login")
public String login() {
return "login";
}
}
I am expecting that my client app is redirected to the custom login page, once login button is pressed my custom AuthenticationProvider will lookup for user in the correct table based on the extra field in the custom login page.
解决方案
对于第一点,您只需为您的WebSecurityConfigurerAdapter
.
添加.formLogin().loginPage("/login").permitAll()
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
推荐阅读
- python - 如何在使用带有 lambda 表达式的 pandas 应用函数时消除类型错误
- swift - 如何快速将 UIView 绘图转换为 GLKView?
- cakephp - 带有 CASE WHEN THEN ELSE 条件的 CakePHP 查询
- c++ - 使用 ffh.getFieldType() == "/Btn" 和 qpdf lib 检查复选框
- c# - 将 Web 应用身份验证转发到 API 服务
- ruby - Chef 服务器从 Chef 工作站返回 404 的刀命令
- cheerio - Cheerio:如何通过数据标签进行选择
- javascript - 只返回 id 名称的 querySelectorAll
- angularjs - AngularJS - 单击模态时自动输入字段的可能性
- c# - 如何在责任链中注入下一个处理程序的依赖关系?