(一)、spring boot security 认证--自定义登录实现
2019-01-07 22:19
681 查看
版权声明:本文为博主原创文章,转载请附上博文链接,谢谢! https://blog.csdn.net/qq_30062125/article/details/86031593
Spring Security文章目录
简介
spring security主要分为两部分,认证(authentication)和授权(authority)。
这一篇主要是认证部分,它由 ProviderManager(AuthenticationManager)实现。具体层次结构如下:
认证的核心就是登录,这里简单介绍下security自定义token登录的实现逻辑,同时兼容用户名密码登录。
大体分为以下几个步骤:
- 自定义AuthenticationToken实现: 不同登录方式使用不同的token
- 自定义AuthenticationProcessingFilter实现:用来过滤指定的登录方式,生成对应的自定义AuthenticationToken实现
- 自定义AuthenticationProvider实现:针对不同登录方式提供的认证逻辑
- 自定义UserDetailsService实现:自定义用户信息查询服务
- WebSecurityConfigurerAdapter声明:security信息配置,将前面的自定义对象注入到流程中。
代码路径
步骤说明
注:仅说明实现方式,逻辑简化处理。
1、自定义AuthenticationProcessingFilter实现
package demo.model; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import java.util.Collection; /** * * @Description: 声明自定义token,是为后面的AuthenticationProvider提供支撑,区分不同类型的处理。 * * @auther: csp * @date: 2019/1/7 下午6:25 * */ public class LoginToken extends AbstractAuthenticationToken { private final String token; public LoginToken(String token) { super(null); this.token = token; } public LoginToken(String token, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.token = token; setAuthenticated(true); } // 这个地方传递下token,逻辑是简化的逻辑,具体可以根据实际场景处理。 // 如jwt token,解析出来username等信息,放到该token中。 @Override public Object getCredentials() { return this.token; } @Override public Object getPrincipal() { return null; } }
2、自定义AuthenticationProcessingFilter实现
package demo.filter; import demo.model.LoginToken; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * * @Description: 自定义filter,用来筛选出来想要的登录方式。 * * @auther: csp * @date: 2019/1/7 下午6:27 * */ public class MyTokenAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private static final String SPRING_SECURITY_RESTFUL_TOKEN = "token"; public static final String SPRING_SECURITY_RESTFUL_LOGIN_URL = "/tokenLogin"; private boolean postOnly = true; // 请求路径声明,url不能被权限拦截。 // 会根据AntPathRequestMatcher 筛选请求,符合条件的才会认为有效 public MyTokenAuthenticationFilter() { super(new AntPathRequestMatcher(SPRING_SECURITY_RESTFUL_LOGIN_URL, null)); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { AbstractAuthenticationToken authRequest; String token = obtainParameter(request, SPRING_SECURITY_RESTFUL_TOKEN); authRequest = new LoginToken(token); // Allow subclasses to set the "details" property setDetails(request, authRequest); // 根据AuthenticationManager校验具体的请求,实际的登录验证触发。 return this.getAuthenticationManager().authenticate(authRequest); } private void setDetails(HttpServletRequest request, AbstractAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } private String obtainParameter(HttpServletRequest request, String parameter) { String result = request.getParameter(parameter); return result == null ? "" : result; } }
3、自定义AuthenticationProvider实现
package demo.provider; import demo.model.LoginToken; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; /** * * @Description: token验证逻辑 * * @auther: csp * @date: 2019/1/7 下午9:05 * */ public class MyTokenProvider implements AuthenticationProvider { UserDetailsService userDetailsService; public MyTokenProvider(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { String token = (authentication.getCredentials() == null) ? "NONE_PROVIDED" : (String) authentication.getCredentials(); // loginToken_user // 这个地方简化处理,实际需要校验token,如jwt token 需要解密 验证信息 if (token.startsWith("loginToken_")) { // 验证下token对不对,然后加载下信息。 Strin 1d25c g userName = token.split("_")[1]; UserDetails user = userDetailsService.loadUserByUsername(userName); LoginToken result = new LoginToken(token, user.getAuthorities()); result.setDetails(authentication.getDetails()); return result; } throw new BadCredentialsException("token无效"); } /** * * @Description: 只处理特定类型的登录 * * @auther: csp * @date: 2019/1/7 下午9:03 * @param authenticationClass * @return: boolean * */ @Override public boolean supports(Class<?> authenticationClass) { return (LoginToken.class .isAssignableFrom(authenticationClass)); } public UserDetailsService getUserDetailsService() { return userDetailsService; } public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } }
4、自定义UserDetailsService实现
package demo.service; import demo.model.UrlGrantedAuthority; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.DisabledException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; 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.Component; import java.util.ArrayList; import java.util.List; /** * * @Description: 用户信息查询逻辑,这里token认证和用户名登录使用同一个service * * @auther: csp * @date: 2019/1/7 下午9:06 * */ @Component public class MyUserDetailsService implements UserDetailsService { private Logger logger = LoggerFactory.getLogger(getClass()); @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { logger.info("用户的用户名: {}", username); List<GrantedAuthority> list = new ArrayList<GrantedAuthority>(); // 模拟下逻辑,简单处理下。 if ("admin".equals(username)) { // 自定义权限实现 UrlGrantedAuthority authority = new UrlGrantedAuthority(null, "/admin/index"); list.add(authority); // 封装用户信息,并返回。参数分别是:用户名,密码,用户权限 User user = new User(username, "123456", list); return user; } else if ("user".equals(username)) { list.add(new SimpleGrantedAuthority("ROLE_USER")); User user = new User(username, "123456", list); return user; } else { throw new DisabledException("用户不存在"); } } }
5、WebSecurityConfigurerAdapter声明
package demo.config; import demo.filter.MyTokenAuthenticationFilter; import demo.provider.MyTokenProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.security.access.AccessDecisionManager; import org.springframework.security.access.vote.AbstractAccessDecisionManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.ObjectPostProcessor; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.WebSecurity; 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.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService myUserDetailsService; // @formatter:off @Override protected void configure(HttpSecurity http) throws Exception { http // 将tokenfilter追加进去,筛选出来tokenLogin逻辑。 .addFilterBefore(getTokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) .logout().logoutUrl("/logout").logoutSuccessUrl("/").and() .formLogin().loginPage("/login").defaultSuccessUrl("/").failureUrl("/login-error").permitAll().and() .authorizeRequests() .antMatchers(MyTokenAuthenticationFilter.SPRING_SECURITY_RESTFUL_LOGIN_URL).permitAll() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/user/**").hasRole("USER") .anyRequest().authenticated(); } // @formatter:on @Override public void configure(WebSecurity web) throws Exception { //忽略请求 不走security filters web.ignoring().antMatchers("/login-error2","/css/**","/info","/health","/hystrix.stream"); } /** * 1、用户验证,指定多个AuthenticationProvider * 实际执行时候根据provider的supports方法判断是否走逻辑 * * 2、如果不覆盖,优先会获取AuthenticationProvider bean作为provider; * 如果没有bean,默认提供DaoAuthenticationProvider * * @param auth */ @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(myTokenProvider()); // 未配置时候用户名密码默认登录provider auth.authenticationProvider(daoAuthenticationProvider()); } @Bean public DaoAuthenticationProvider daoAuthenticationProvider(){ DaoAuthenticationProvider provider1 = new DaoAuthenticationProvider(); // 设置userDetailsService provider1.setUserDetailsService(myUserDetailsService); // 禁止隐藏用户未找到异常 provider1.setHideUserNotFoundExceptions(false); // 使用BCrypt进行密码的hash // provider1.setPasswordEncoder(myEncoder()); return provider1; } /** * * @Description: 自定义token方式认证逻辑provider * * @auther: csp * @date: 2019/1/7 下午9:18 * @return: demo.provider.MyTokenProvider * */ @Bean public MyTokenProvider myTokenProvider() { return new MyTokenProvider(myUserDetailsService); } // @Bean public BCryptPasswordEncoder myEncoder(){ return new BCryptPasswordEncoder(6); } /** * token登录过滤器,用来筛选出来token登录方式。 */ @Bean public MyTokenAuthenticationFilter getTokenAuthenticationFilter() { MyTokenAuthenticationFilter filter = new MyTokenAuthenticationFilter(); try { // 使用的是默认的authenticationManager filter.setAuthenticationManager(this.authenticationManagerBean()); } catch (Exception e) { e.printStackTrace(); } // filter.setAuthenticationSuccessHandler(new MyLoginAuthSuccessHandler()); filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/")); filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login-error2")); return filter; } }
6、验证
- 用户名密码登录:
admin 123456
user 123456
- token登录:
user登录:
http://127.0.0.1:9999/tokenLogin?token=loginToken_user
admin登录:
http://127.0.0.1:9999/tokenLogin?token=loginToken_admin
相关文章推荐
- spring集成shiro实现登录认证自定义验证功能(认证采用国密SM4算法)
- (七)、SpringBoot + SpringSecurity 简单登录认证
- SpringBoot + Spring Security 学习笔记(一)自定义基本使用及个性化登录配置
- spring-boot集成spring-security的oauth2实现github登录网站的示例
- spring实战-Spring-security实现用户权限认证登录
- SpringBoot整合Shiro实现登录认证的方法
- spring boot + mybatis + spring security(自定义登录界面)环境搭建
- spring-security认证过程的分析及自定义登录
- SpringBoot2.0整合SpringSecurity实现自定义表单登录
- spring boot + mybatis + spring security(自定义登录界面)环境搭建
- Spring boot + Spring Security 实现用户登录管理
- [安全] 使用 SpringBoot + SpringSecurity 做登录认证
- SpringBoot + SpringSecurity 短信验证码登录功能实现
- spring-security 个性化用户认证流程——自定义登录页面(可配置)
- spring boot---WebFilter注解 实现自定义登录过滤器
- springboot+springsecurity+mybatis+thymeleaf实现用户登录和权限过程中的坑
- (二)、spring boot security 授权--自定义授权实现
- Spring Boot+Spring Security+JWT 实现 RESTful Api 权限控制
- Spring boot 2.x+oauth2实现单点登录:基础准备之OAuth 2.0
- SpringBoot/SpringMVC整合Shiro(一):实现登录与注册(MD5加盐加密)