标签:parameter nbsp ack 验证 就是 isa 自定义 form security+
单点登录中目前比较流行的一种使用方式,就是springsecurity+jwt实现无状态下用户登录;下面是对于Spring-Security进行单点登录使用token来进行交互的一种方式。第一次写博客请多多指教如果有更好的方式或者是错误的点麻烦请指教。
Spring-Security的主要几个实现类
WebSecurityConfigurerAdapter这个类主要是用来对Spring Security的请求,拦截等进行一些配置
ExcpeitonMappingAuthenticationFailureHandler 这个类主要是对登录失败进行处理
SaveRequestAwareAuthenticationSucessHandler 这个类主要是对登录成功进行处理
UserDetailsService 这个类主要是用于对权限的校验还有登录的校验
BasicAuthenticationFilter 自定义拦截蓝主要是用于对token进行校验然后决定是否放行
从WebSecurityConfigurerAdapter进行请求,登录等请求进行配置
@Component public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired LoginAuthenticationSuecssHandler loginAuthenticationSuecssHandler; @Autowired LoginAuthenticationFailHandler loginAuthenticationFailHandler; @Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/authentication/require") .loginProcessingUrl("/authentication/form") .successHandler(loginAuthenticationSuecssHandler) .failureHandler(loginAuthenticationFailHandler) .and() .authorizeRequests()//这个单词的意思是下面都是授权配置 .antMatchers("/authentication/require","/authentication/form").permitAll()//把授权信息放开 .anyRequest() //任何请求都被授权 .authenticated()//都需要身份认证 .and() .addFilter(new AuthenticationTokenFilter(authenticationManager())) .authorizeRequests() .antMatchers( "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js" ).permitAll() .and() .csrf().disable(); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/login.html"); } }
设置自定义登录跳转
@RestController public class LoginController { private Logger logger = LoggerFactory.getLogger(getClass()); private RequestCache requestCache = new HttpSessionRequestCache(); private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); @RequestMapping("/authentication/require") @ResponseStatus(code = HttpStatus.UNAUTHORIZED) public ResponseVo requireAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException { logger.info("requireAuthentication:当前用户未登录:访问路径{}"+request.getServletPath()); SavedRequest savedRequest = requestCache.getRequest(request, response); if (savedRequest != null){ String redirectUrl = savedRequest.getRedirectUrl(); if (StringUtils.endsWithIgnoreCase(redirectUrl, ".html")) { logger.info("requireAuthentication:当前用户是PcWeb端请求:{}正在重定向"); response.sendRedirect("http://localhost:9050/login.html"); } } logger.info("requireAuthentication:访问的服务需要身份认证,请引导用户到登录页"); return ResponseMeaage.error(SysConstant.LOGIN_FALL); } }
对登录的账号密码进行对应的校验
@Component public class MyUserDetailsService implements UserDetailsService { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired @Qualifier("dbUserMapper") DbUserMapper dbUserMapper; @Autowired @Qualifier("httpServletRequest") HttpServletRequest httpServletRequest; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { if (!StringUtils.isEmpty(username)){
//自定义拦截器进行处理的时候会有bean注入不了的情况 if (dbUserMapper == null && httpServletRequest == null){ dbUserMapper = SpringUtils.getBean(DbUserMapper.class); } DbUser dbUser = dbUserMapper.selectOne(new QueryWrapper<DbUser>().eq("username", username)); if (dbUser != null){ List<GrantedAuthority> list = new ArrayList<GrantedAuthority>(); GrantedAuthority au = new SimpleGrantedAuthority("ROLE_USER"); GrantedAuthority at = new SimpleGrantedAuthority("ROOT"); String password = dbUser.getPassword(); logger.info("loadUserByUsername:当前数据库密码:{}"+ password); return new User(username,password,list); }else{ throw new UsernameNotFoundException("用户不存在"); } }else{ throw new UsernameNotFoundException("用户名为空"); } } }
对登录成功的类进行返回对应jwt加密过的token
public class LoginAuthenticationSuecssHandler extends SavedRequestAwareAuthenticationSuccessHandler { @Autowired private ObjectMapper objectMapper; private Logger logger = LoggerFactory.getLogger(getClass()); @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException { String header = request.getHeader("user-agent"); logger.info("LoginAuthenticationSuecssHandler:当前登录的用户:{}"+authentication.getName()); String password = request.getParameter("password"); String token = JWTTest.getJwtBuilder(password, authentication.getName(), JWTTest.getKey()); logger.info("LoginAuthenticationSuecssHandler:加密后的token:{}"+token); if (header.indexOf("Android") != -1) { response.getWriter().write(objectMapper.writeValueAsString(ResponseMeaage.sucess(token,1, SysConstant.LOGIN_SUCCESS))); }else if (header.indexOf("iPhone") != -1 || header.indexOf("iPad") != -1){ response.getWriter().write(objectMapper.writeValueAsString(ResponseMeaage.sucess(token,1, SysConstant.LOGIN_SUCCESS))); }else{ response.getWriter().write(objectMapper.writeValueAsString(ResponseMeaage.sucess(token,1, SysConstant.LOGIN_SUCCESS))); } } }
登录失败的进行对应的处理
@Component public class LoginAuthenticationFailHandler extends ExceptionMappingAuthenticationFailureHandler { private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired ObjectMapper objectMapper; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { String header = request.getHeader("user-agent"); if (header.indexOf("Android") != -1) { logger.info("onAuthenticationFailure:Phone Model:Android"); }else if (header.indexOf("iPhone") != -1 || header.indexOf("iPad") != -1){ logger.info("onAuthenticationFailure:Phone Model:iPhone"); }else{ logger.info("onAuthenticationFailure:Web{}"+header); response.sendRedirect("http://localhost:9030/index.html"); } logger.info("LoginAuthenticationFailHandler:当前用户登录失败{}"+request.getParameter("username")); ResponseVo responseVo = ResponseMeaage.error("用户输入密码错误"); response.getWriter().write(objectMapper.writeValueAsString(responseVo)); } }
自定义拦截器进行token的校验
@Component public class AuthenticationTokenFilter extends BasicAuthenticationFilter { private Logger logger = LoggerFactory.getLogger(getClass()); public AuthenticationTokenFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("BasicAuthenticationFilters"); String tokenHeader = request.getParameter("token"); System.out.println("tokenHeader:"+tokenHeader); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "*"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers:x-requested-with,content-type"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=utf-8"); // 如果请求头中没有Authorization信息则直接放行了 if (StringUtils.isEmpty(tokenHeader)) { chain.doFilter(request, response); return; } try { SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader)); logger.info("LoginAuthenticationSuecssHandler:设置Token成功"); super.doFilterInternal(request, response, chain); }catch (Exception e){ logger.info("当前token验证信息出错:token{}",tokenHeader); } chain.doFilter(request, response); // 如果请求头中有token,则进行解析,并且设置认证信息 } private UsernamePasswordAuthenticationToken getAuthentication(String token) { //解析Token时将“Bearer ”前缀去掉 Claims jwtToken = JWTTest.cc(token, JWTTest.getKey()); String username = jwtToken.get("username").toString(); logger.info("getAuthentication:username{}",username); if (!StringUtils.isEmpty(username)){ return new UsernamePasswordAuthenticationToken(username, null, null); } return null; } }
自定义拦截器Bean获取不到使用该方法进行获取
@Component public class SpringUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (SpringUtils.applicationContext == null) { SpringUtils.applicationContext = applicationContext; } } public static ApplicationContext getApplicationContext() { return applicationContext; } //根据name public static Object getBean(String name) { return getApplicationContext().getBean(name); } //根据类型 public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } }
JWT进行简单的加密
public class JWTTest { public static Key getKey(){ Key key = new SecretKeySpec("javastack".getBytes(), SignatureAlgorithm.HS512.getJcaName()); return key; } public static String getJwtBuilder(String password,String user,Key key){ Map<String, Object> userMap = new HashMap(); userMap.put("username",user); String jwtBuilder = Jwts.builder() .setClaims(userMap) .setId(UUID.randomUUID().toString()) .setIssuedAt(new Date(System.currentTimeMillis())) .setSubject(password) .signWith(SignatureAlgorithm.HS256, key.toString()).compact(); return jwtBuilder; } public static String getJwtBuilder(String user,Key key){ Map<String, Object> userMap = new HashMap<>(); userMap.put("username",user); String jwtBuilder = Jwts.builder() .setClaims(userMap) .setId(UUID.randomUUID().toString()) .setIssuedAt(new Date(System.currentTimeMillis())) .setSubject(userMap.get("username").toString()) .signWith(SignatureAlgorithm.HS256, key.toString()).compact(); return jwtBuilder; } public static Claims cc(String jwtBuilder,Key key){ Jws<Claims> claimsJws = Jwts.parser().setSigningKey(key.toString()).parseClaimsJws(jwtBuilder); JwsHeader header = claimsJws.getHeader(); Claims claims = claimsJws.getBody(); System.out.println("jwt header:" + header); System.out.println("jwt body:" + claims); System.out.println("jwt body user-id:" + claims.get("password", String.class)); return claims; } }
Springboot+Spring-Security+JWT Sso单点登录
标签:parameter nbsp ack 验证 就是 isa 自定义 form security+
原文地址:https://www.cnblogs.com/xiaoguifu/p/14367977.html