在spring cloud 的oauth2认证中,有一个用户认证服务auth,提供客户端的认证,由于oauth2有多种授权方式,不同的授权采用的方式就不一样了。
在实际业务中,比如有个应用A,有自己的数据库A,需要auth授权后才能登陆,PC端登录的时候采用的是授权码模式,使用 @EnableOAuth2Sso 注解标记一个 WebSecurityConfigurerAdapter 类。当登录认证成功后会广播一个event事件,这个事件可以监听到,所以我们采用的是监听InteractiveAuthenticationSuccessEvent事件,这个是通过自动交互的手段来登录成功,比如cookie自动登录。具体实现细节如下,实际应用采用的是注释掉的代码,两种都可以参考:
@EventListener
public void authSuccessListener(InteractiveAuthenticationSuccessEvent event){
System.out.println("哎呦喂,登录成功了");
Authentication authentication=SecurityContextHolder.getContext().getAuthentication();
//通用替换,针对用户名密码登录的
if(authentication instanceof UsernamePasswordAuthenticationToken){
UsernamePasswordAuthenticationToken originToken= (UsernamePasswordAuthenticationToken) authentication;
String username= originToken.getName();
System.out.println(username);
//查找用户,这里直接模拟查到了用户,根据需求进行替换
Person person=new Person(username,20);
UsernamePasswordAuthenticationToken token=new UsernamePasswordAuthenticationToken(originToken.getPrincipal(),"N/A",originToken.getAuthorities());
token.setDetails(person);
SecurityContextHolder.getContext().setAuthentication(token);
}
//auth2替换
//替换oauth认证的信息里的details,这里就不展示了
/* if (authentication instanceof OAuth2Authentication) {
OAuth2Authentication originalOAuth2Authentication = (OAuth2Authentication) authentication;
if (!originalOAuth2Authentication.isClientOnly()) {
Authentication userAuthentication = originalOAuth2Authentication.getUserAuthentication();
if (userAuthentication instanceof UsernamePasswordAuthenticationToken) {
UsernamePasswordAuthenticationToken originalUsernamePasswordAuthentication = (UsernamePasswordAuthenticationToken) userAuthentication;
String username = (String) originalUsernamePasswordAuthentication.getPrincipal();
//可以根据username查找用户,这里模拟获取用户
Person person=new Person("二狗子",18);
if (person != null) {
//替换用户信息,权限信息根据自己的需求替换,这里直接取原来的
UsernamePasswordAuthenticationToken usernamePasswordAuthentication = new UsernamePasswordAuthenticationToken(originalUsernamePasswordAuthentication.getPrincipal(), "N/A", originalUsernamePasswordAuthentication.getAuthorities());
usernamePasswordAuthentication.setDetails(person);
OAuth2Authentication oauth2Authentication = new OAuth2Authentication(originalOAuth2Authentication.getOAuth2Request(), usernamePasswordAuthentication);
oauth2Authentication.setDetails(originalOAuth2Authentication.getDetails());
SecurityContextHolder.getContext().setAuthentication(oauth2Authentication);
}
}
}
}*/
}
但是在APP登录的时候采用的授权方式是密码,这样认证的时候是根据认证token,只是一个token没有像pc端那样有cookie去自动验证,服务器是通过资源服务器认证的,只要token通过就可以访问被资源服务器保护的资源,这里都是/api/的接口。这种情况下就不能监听登录事件了,要在每次验证通过后去替换oauthAuthentication里面的details了,这样接口获取本应用当前登录用户的时候就可以直接获取了。那么如何实现认证成功后替换呢,根据spring security的尿性,增加一个filter,在最后一个filter之前替换。(注意:自定义过滤器交给spring托管可能出现doFilter被执行两次的问题,可以加个标记解决)
@Component
public class CustomerSecurityFilter extends GenericFilterBean {
//加个标记,防止被执行两次
//在spring容器托管的GenericFilterBean的bean,都会自动加入到servlet的filter chain,而我们还额外把filter加入到了spring security的
//最后一个Filter之前。而spring security也是一系列的filter,在mvc的filter之前执行。因此在鉴权通过的情况下,就会先后各执行一次。
private static final String FILTER_APPLIED = "__spring_security_customerFilter_filterApplied";
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
if(servletRequest.getAttribute(FILTER_APPLIED)!=null){
filterChain.doFilter(servletRequest,servletResponse);
return;
}
System.out.println("哎呦呵,来啦");
//替换用户信息,具体替换步骤参考上一个替换,这个用户最好存入缓存,毕竟过滤器过滤的请求挺多,每次都要查询很坑的
servletRequest.setAttribute(FILTER_APPLIED,true);
filterChain.doFilter(servletRequest,servletResponse);
}
}
@Autowired
private CustomerSecurityFilter customerSecurityFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/chat")
.permitAll()
.and()
.logout()
.permitAll()
.and()
.addFilterBefore(customerSecurityFilter,SwitchUserFilter.class);
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/100307.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...