spring security实现登录,springboot security 单点登录

  spring security实现登录,springboot security 单点登录

  00-1010后台Spring安全实现已经有了单点登录页面。Spring Security怎么登录?不登录能获得权限吗?认证继续分析结论。如何手动登录Spring Security?结论摘要附参考文献。

  00-1010在配置中心添加权限功能

  目前配置中心已经包含单点登录功能,可以通过统一的页面登录。登录后,用户、角色、权限表CRUD、授权等。将用户写入用户表RBAC已经全部完成。希望你不用重新登录就能使用SpringSecurity的权限控制。

  00-1010春季安全的两个主要功能:认证和授权

  Spring Security中的主类验证(认证)你是谁,验证(授权)你能做什么AuthenticationManager?

  00-1010让我们简单看一下Spring Security的架构,以及如何对其进行认证和授权。

  每个过滤器人都应该知道这属于Servlet的范畴。Servlet过滤器可以动态地拦截请求和响应,以转换或使用请求或响应中包含的信息。

  DelegatingFilterProxy是属于春天安全的过滤器。

  通过这个过滤器,Spring Security可以从请求中获取URL,以确定它是否需要身份验证才能访问,或者它是否需要特定的权限才能访问。

  

目录

Spring安全官方文档-授权架构是这么说的,GrantedAuthority(也就是你拥有的权限)由AuthenticationManager写入认证对象,然后由AuthorizationManager用于授权。

 

  AuthenticationManager将GrantedAuthority对象插入到Authentication对象中,然后AuthorizationManager在做出授权决定时读取这些对象。

  为了解决我们的问题,即使我只想使用授权认证功能,我也必须创建一个认证。先看看这个物体:

  

背景

认证包含三个字段:

 

  主体代表用户凭证和用户密码授权,有两个功能。

  AuthenticationManager的参与仅用于存储用户信息,准备对AuthenticationManager的参与进行身份验证,通过身份验证的用户信息,可以从securitycontextto中获取SecurityContextholder和SecurityContextHolder来存储身份验证。通常使用线程全局变量ThreadLocal,即认证完成后将认证放入securitycontext,然后在同一个线程的整个进程中获取认证信息,方便认证。

  00-1010看到这个可以得到,要实现不登录的权限认证,只需要手动创建一个认证,然后放入SecurityContext。先试试。大致流程如下。对于每个请求,

  获得sso登录的用户读取用户、角色、权限,并将身份验证写入SecurityContext。当请求完成时,SecurityContext将被清除,因为它是ThreadLocal,否则它可能被其他用户使用。同时,Spring Security的配置为所有允许访问的URL添加了一个过滤器,代码如下:

  导入javax . servlet . *;导入javax . servlet . annotation . web filter;导入javax . servlet . http . http servlet request;导入Java . io . io exception;导入java.u

  til.HashMap;import java.util.List;import java.util.Map;import java.util.stream.Collectors;@WebFilter( urlPatterns = "/*", filterName = "reqResFilter" )public class ReqResFilter implements Filter{@Autowiredprivate SSOUtils ssoUtils;@Autowiredprivate UserManager userManager;@Autowiredprivate RoleManager roleManager;@Overridepublic void init( FilterConfig filterConfig ) throws ServletException{}@Overridepublic void doFilter( ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain )throws IOException, ServletException{setAuthentication(servletRequest);filterChain.doFilter( servletRequest, servletResponse );clearAuthentication();}@Overridepublic void destroy(){}private void setAuthentication( ServletRequest request ){Map<String, String> 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<Role> userRole = userManager.findUserRole( username );List<Long> roleIds = userRole.stream().map( Role::getId ).collect( Collectors.toList() );List<Permission> rolePermission = roleManager.findRolePermission( roleIds );List<SimpleGrantedAuthority> 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;@Servicepublic class UserDetailsServiceImpl implements UserDetailsService{private static final Logger logger = LoggerFactory.getLogger( UserDetailsServiceImpl.class );@Autowiredprivate UserManager userManager;@Autowiredprivate RoleManager roleManager;@Overridepublic 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<Role> userRole = userManager.findUserRole( username );List<Long> roleIds = userRole.stream().map( Role::getId ).collect( Collectors.toList() );List<Permission> rolePermission = roleManager.findRolePermission( roleIds );return rolePermission.stream().map( one -> new SimpleGrantedAuthority( one.getName() ) ).collect( Collectors.toList() );}}
@Override@Beanpublic 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{@Autowiredprivate UserDetailsService userDetailsService;@Overrideprotected void configure( HttpSecurity http ) throws Exception{http.cors().and().csrf().disable().sessionManagement().and().authorizeRequests().anyRequest().permitAll().and().exceptionHandling().accessDeniedHandler( new SimpleAccessDeniedHandler() );}@Override@Beanpublic AuthenticationManager authenticationManagerBean() throws Exception{DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();daoAuthenticationProvider.setUserDetailsService( userDetailsService );daoAuthenticationProvider.setPasswordEncoder( NoOpPasswordEncoder.getInstance() );return new ProviderManager( daoAuthenticationProvider );}@Beanpublic 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;}}

 

  

参考

Spring Security官方文档-授权架构How to login user from java code in Spring Security?到此这篇关于Spring Security使用单点登录的权限功能的文章就介绍到这了,更多相关Spring Security单点登录权限内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!

 

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: