范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

腾讯大佬单点登录系统使用SpringSecurity的权限功能

  单点登录系统使用Spring Security的权限功能背景
  在配置中心增加权限功能 目前配置中心已经包含了单点登录功能,可以通过统一页面进行登录,登录完会将用户写入用户表 RBAC的用户、角色、权限表CRUD、授权等都已经完成 希望不用用户再次登录,就可以使用SpringSecurity的权限控制 Spring Security
  Spring Security最主要的两个功能: 认证和授权
  功能
  解决的问题
  Spring Security中主要类
  认证(Authentication)
  你是谁
  AuthenticationManager
  授权(Authorization)
  你可以做什么
  AuthorizationManager 实现
  在这先简单了解一下Spring Security的架构是怎样的,如何可以认证和授权的
  过滤器 大家应该都了解,这属于Servlet的范畴,Servlet 过滤器可以动态地拦截请求和响应,以变换或使用包含在请求或响应中的信息
  DelegatingFilterProxy 是一个属于Spring Security的过滤器
  通过这个过滤器,Spring Security就可以从Request中获取URL来判断是不是需要认证才能访问,是不是得拥有特定的权限才能访问。 已经有了单点登录页面,Spring Security怎么登录,不登录可以拿到权限吗
  Spring Security官方文档-授权架构中这样说,GrantedAuthority(也就是拥有的权限)被AuthenticationManager写入Authentication对象,后而被AuthorizationManager用来做权限认证
  The GrantedAuthority objects are inserted into the Authentication object by the AuthenticationManager and are later read by either the AuthorizationManager when making authorization decisions.
  为了解决我们的问题,即使我只想用权限认证功能,也得造出一个Authentication,先看下这个对象:Authentication
  Authentication包含三个字段:principal,代表用户credentials,用户密码authorities,拥有的权限
  有两个作用:AuthenticationManager的入参,仅仅是用来存用户的信息,准备去认证AuthenticationManager的出参,已经认证的用户信息,可以从SecurityContext获取
  SecurityContext和SecurityContextHolder用来存储Authentication, 通常是用了线程全局变量ThreadLocal, 也就是认证完成把Authentication放入SecurityContext,后续在整个同线程流程中都可以获取认证信息,也方便了认证继续分析
  看到这可以得到,要实现不登录的权限认证,只需要手动造一个Authentication,然后放入SecurityContext就可以了,先尝试一下,大概流程是这样,在每个请求上获取sso登录的用户读取用户、角色、权限写入Authentication将Authentication写入SecurityContext请求完毕时将SecurityContext清空,因为是ThreadLocal的,不然可能会被别的用户用到同时Spring Security的配置中是对所有的url都允许访问的
  加了一个过滤器,代码如下:import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors;  @WebFilter( urlPatterns = "/*", filterName = "reqResFilter" ) public class ReqResFilter implements Filter{  	@Autowired 	private SSOUtils ssoUtils; 	@Autowired 	private UserManager userManager; 	@Autowired 	private RoleManager roleManager;  	@Override 	public void init( FilterConfig filterConfig ) throws ServletException{  	}  	@Override 	public void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain ) 			throws IOException, ServletException{ 		setAuthentication(servletRequest); 		filterChain.doFilter( servletRequest, servletResponse ); 		clearAuthentication(); 	}  	@Override 	public void destroy(){  	}  	private void setAuthentication( ServletRequest request ){  		Map data; 		try{ 			data = ssoUtils.getLoginData( ( HttpServletRequest )request ); 		} 		catch( Exception e ){ 			data = new HashMap<>(); 			data.put( "name", "visitor" ); 		} 		String username = data.get( "name" ); 		if( username != null ){ 			userManager.findAndInsert( username ); 		} 		List userRole = userManager.findUserRole( username ); 		List roleIds = userRole.stream().map( Role::getId ).collect( Collectors.toList() ); 		List rolePermission = roleManager.findRolePermission( roleIds ); 		List authorities = rolePermission.stream().map( one -> new SimpleGrantedAuthority( one.getName() ) ).collect( 				Collectors.toList() );  		UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( username, "", authorities ); 		SecurityContextHolder.getContext().setAuthentication( authenticationToken ); 	}  	private void clearAuthentication(){  		SecurityContextHolder.clearContext(); 	} }
  从日志可以看出,Principal: visitor,当访问未授权的接口被拒绝了16:04:07.429 [http-nio-8081-exec-9] DEBUG org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@cc4c6ea0: Principal: visitor; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: CHANGE_USER_ROLE, CHANGE_ROLE_PERMISSION, ROLE_ADD ... org.springframework.security.access.AccessDeniedException: 不允许访问 结论
  不登录是可以使用Spring Security的权限,从功能上是没有问题的,但存在一些别的问题性能问题,每个请求都需要请求用户角色权限数据库,当然可以利用缓存优化我们写的过滤器其实也是Spring Security做的事,除此之外,它做了更多的事,比如结合HttpSession, Remember me这些功能
  我们可以采取另外一种做法,对用户来说只登录一次就行,我们仍然是可以手动用代码再去登录一次Spring Security的如何手动登录Spring Security
  How to login user from java code in Spring Security? 从这篇文章从可以看到,只要通过以下代码即可	private void loginInSpringSecurity( String username, String password ){  		UsernamePasswordAuthenticationToken loginToken = new UsernamePasswordAuthenticationToken( username, password ); 		Authentication authenticatedUser = authenticationManager.authenticate( loginToken ); 		SecurityContextHolder.getContext().setAuthentication( authenticatedUser ); 	}
  和上面我们直接拿已经认证过的用户对比,这段代码让Spring Security来执行认证步骤,不过需要配置额外的AuthenticationManager和UserDetailsServiceImpl,这两个配置只是AuthenticationManager的一种实现,和上面的流程区别不大,目的就是为了拿到用户的信息和权限进行认证import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service;  import java.util.List; import java.util.stream.Collectors;  @Service public class UserDetailsServiceImpl implements UserDetailsService{  	private static final Logger logger = LoggerFactory.getLogger( UserDetailsServiceImpl.class );  	@Autowired 	private UserManager userManager;  	@Autowired 	private RoleManager roleManager;  	@Override 	public UserDetails loadUserByUsername( String username ) throws UsernameNotFoundException{  		User user = userManager.findByName( username ); 		if( user == null ){ 			logger.info( "登录用户[{}]没注册!", username ); 			throw new UsernameNotFoundException( "登录用户[" + username + "]没注册!" ); 		} 		return new org.springframework.security.core.userdetails.User( user.getUsername(), "", getAuthority( username ) ); 	}  	private List<? extends GrantedAuthority> getAuthority( String username ){  		List userRole = userManager.findUserRole( username ); 		List roleIds = userRole.stream().map( Role::getId ).collect( Collectors.toList() ); 		List rolePermission = roleManager.findRolePermission( roleIds ); 		return rolePermission.stream().map( one -> new SimpleGrantedAuthority( one.getName() ) ).collect( Collectors.toList() ); 	} } 	@Override 	@Bean 	public AuthenticationManager authenticationManagerBean() throws Exception{  		DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); 		daoAuthenticationProvider.setUserDetailsService( userDetailsService ); 		daoAuthenticationProvider.setPasswordEncoder( NoOpPasswordEncoder.getInstance() ); 		return new ProviderManager( daoAuthenticationProvider ); 	} 结论
  通过这样的方式,同样实现了权限认证,同时Spring Security会将用户信息和权限缓存到了Session中,这样就不用每次去数据库获取总结
  可以通过两种方式来实现不登录使用SpringSecurity的权限功能手动组装认证过的Authentication直接写到SecurityContext,需要我们自己使用过滤器控制写入和清除手动组装未认证过的Authentication,并交给Spring Security认证,并写入SecurityContext附
  Spring Security是如何配置的,因为只使用权限功能,所有允许所有的路径访问(我们的单点登录会限制接口的访问)import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.password.NoOpPasswordEncoder; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;  import java.util.Arrays; import java.util.Collections;    @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter{  	@Autowired 	private UserDetailsService userDetailsService;  	@Override 	protected void configure( HttpSecurity http ) throws Exception{  		http 				.cors() 				.and() 				.csrf() 				.disable() 				.sessionManagement() 				.and() 				.authorizeRequests() 				.anyRequest() 				.permitAll() 				.and() 				.exceptionHandling() 				.accessDeniedHandler( new SimpleAccessDeniedHandler() ); 	}   	@Override 	@Bean 	public AuthenticationManager authenticationManagerBean() throws Exception{  		DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); 		daoAuthenticationProvider.setUserDetailsService( userDetailsService ); 		daoAuthenticationProvider.setPasswordEncoder( NoOpPasswordEncoder.getInstance() ); 		return new ProviderManager( daoAuthenticationProvider ); 	}  	@Bean 	public CorsConfigurationSource corsConfigurationSource(){  		CorsConfiguration configuration = new CorsConfiguration(); 		configuration.setAllowedOrigins( Collections.singletonList( "*" ) ); 		configuration.setAllowedMethods( Arrays.asList( "GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS" ) ); 		configuration.setAllowCredentials( true ); 		configuration.setAllowedHeaders( Collections.singletonList( "*" ) ); 		configuration.setMaxAge( 3600L ); 		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 		source.registerCorsConfiguration( "/**", configuration ); 		return source; 	}  }

兔年开运,会买的人都在香港买什么?过年虽说有假放,但好像完全闲不下来啊?比如说,明天年初五,是送穷迎财神的大日子。我一个香港local朋友,从今天就起了个大早,忙得团团转。毕竟事关一年的财运呀!不过今天是要给大家盘勇士真的需要交易得到玻尔特尔或者特纳吗赛季至今,作为卫冕冠军的勇士,当朝太子怀斯曼已然要被剥夺东宫资格,只差官宣而已。又一轮东部客场之旅,负公牛被武契维奇赛季新高的4010直接锤爆险胜奇才靠着库里极致输出拿下但也难掩连澳网综合斯维亚特克强势梅德韦杰夫脆败新华社墨尔本1月20日电(记者郝亚琳韦骅)2023年澳网20日开始男女单第三轮的争夺。目前排名最高的种子选手西西帕斯和斯维亚特克继续强势晋级,两届澳网亚军梅德韦杰夫连输三盘负于美国塌房!女子晒吴兴涵穿国足T恤隐婚表白老婆爱你!特别想你睡不着1月21日消息,此前足协杯决赛中,山东泰山队2比1逆转浙江队夺得足协杯3连冠。比赛中,一位女子大闹球迷看台,炮轰山东泰山球员吴兴涵骗钱骗感情。日前,该女子实名曝光吴兴涵,在社交媒体他俩,同框拥抱!第37次梅罗对决无关乎输赢,只关乎情怀,关乎享受比赛,关乎彼此尊重。北京时间1月20日凌晨,利雅得明星联队与大巴黎这场友谊赛让曼城4比2逆转热刺皇马巴萨出战国王杯都黯然失色。C罗脱沃尔17年我们能把詹姆斯打爆!骑士队季后赛最怕遇到的是奇才队头条创作挑战赛沃尔最近在参加一档访谈节目时表示你可以问问17年的骑士球员,当时季后赛他们最不希望遇到的就是奇才,我们能把勒布朗打爆了,我(沃尔)和欧文不相伯仲,比尔肯定比Jr强,我一夜10大转会动态切尔西官宣冬窗第6签,阿尔维斯遭俱乐部解约北京时间1月21日,冬季转会窗口开启已有20天时间,各支球队引援迎来了高潮阶段。刚刚过去的这个夜晚,多支球队官宣新援加盟,切尔西继续大手笔交易,阿森纳也有了动作,马竞拿下荷兰国脚德新任主帅乔尔杰维奇全盘否定了杜锋的用人标准温馨提示笔者的文章被剽窃者搬运很多,在笔者无可奈何情况下,把文章中的部分图片添加了原创作者執筆論紅塵的字样,还请读者能够理解和支持!祝新年快乐!新一届中国男篮大名单出炉之后,那真是国乒肖战孤注一掷押宝王楚钦,刘国梁提前布局,王曼昱有点惨国乒总教头李隼在接受采访时公布了国乒主力的主管教练。值得一提的是,国乒金牌教练肖战一对一辅导王楚钦,这对外释放了一个很强的信号,肖战除了担任混双组长外,还专门训练王楚钦,其用意大家三大毒瘤集体入狱,天津天海可以含笑九泉了张鹭丁勇刘奕三个中国足坛耻辱性的人物,曾经也是风云人物。三个人里应外合导致不欠薪的天津天海解散,球员被贱卖,球队资产被他们私吞。张鹭是一个劣迹斑斑的球员,多到数不胜数。欺负小球员,耗时5小时45分钟,大心脏穆雷澳网上演超级逆转穆雷生涯第11次完成输二追三。图新华社新京报讯(首席记者孙海光)北京时间1月20日晨,2023年澳大利亚网球公开赛迄今最精彩的一场比赛诞生了,35岁的穆雷以3比2超级大逆转科基纳基
台湾环岛游第七站垦丁,壮阔的猫鼻头与鹅銮鼻垦丁位于中国台湾最南端的屏东县,有台湾的天涯海角之称。它地属热带气候,平均年气温24度,有热带雨林稀有植物和种类繁多的昆虫。由于三面环海的缘故,形成了特殊的地形地貌。离开高雄后,我北海四道菜老板的黑暗料理就是这家海鲜店广西北海已经通报游客吃4个菜花1500元,店家被停业整顿立案处罚,带客出租车司机被罚款限期停运,今天来说对广大游客同志是个好消息。今天笔者就和大伙给扒一扒这家店的黑暗博贺半岛换新貌融湾强带争先锋2022年下半年以来,茂名滨海新区博贺镇按照茂名市经济发展战略部署,抢抓广东滨海旅游公路茂名先行段通车机遇,灵活将半岛景观资源串珠成链,构筑了一条又一条富有特色的滨海旅游生态廊道,冬游梵净山,感受原始洪荒梵净山位于贵州省东北部的铜仁地区,海拔2572米,系武陵山脉主峰国家级自然保护区联合国人与生物圈保护网成员。原始洪荒是梵净山的景观特征,全境山势雄伟层峦叠嶂,溪流纵横飞瀑悬泻,标志2022年新生儿爆款名字出炉,这些耳熟能详的好名字已经烂大街文菁妈01hr名字所取,根于心意,沿于时尚,因时变迁!中国人的姓名和外国人的姓名还是不太一样的,中国的姓名是中华名文化的脉承之一。比如在菁妈的村里面,所有村上的人都是姓吴的,也就是你想有美好的明天吗春节假期也结束,今日是节后工作第一天,或许你还沉浸在春节的热闹里,但新的征程却已拉开帷幕。庄子说人生天地之间,若白驹过隙,忽然而已。李大钊曾说世间最可贵的就是今,最易丧失得也是今。新生宝宝洗澡的优选打开方式新生宝宝浑身软乎乎的,那么萌又那么脆弱,真是捧在手心怕摔了,含在嘴里怕化了!给他洗澡,真是太难了!难,难在不知道怎么下手,是吧?你要是掌握了要领,那你就多了一个有趣又有爱的轻松亲子过年返京记互联网平台合伙人王彦翔期待事业大展宏兔北京日报客户端记者李松林大年初六早上5点,天空还是漆黑。王彦翔起床洗漱,与父母简单告别。从宁夏村里返程北京需要多次转车,但与过去三年不同,这一次离家,他心里多了几分安稳和期待。大西佳能(中国)伊藤裕之华南市场有活力有潜力佳能充满期待作为大众传统认知中的影像企业,佳能在中国已经深耕了超过25年。身为中国消费者的老朋友,佳能(中国)除了给中国消费者带来影像产品外,如今在直播医疗等等的行业中,都可以看到佳能的身影。2023年iPhone卡贴机科普解锁教程汇总,不要期待黑解,建议收藏今天是2023年大年初八,相信很多的小伙伴已经到了工作岗位了,数码盖饭祝福大家2023年,开工大吉!财源滚滚,一年发到底。春节假期前有不少用户购买了iPhone卡贴机,但是带着卡贴春节后宝宝喊牙疼?含氟牙膏要怎么选?今天是大年初八,笨爸爸给大家拜个晚年,感谢大家一直以来的支持和陪伴,祝大家兔年大吉!春节期间,你家宝宝是不是也开启了吃吃喝喝模式?糖果饼干薯片饮料各种甜的黏的酸的食物,宝宝吃得不亦