留一份前后分离SpringSecurity基础配置
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
package com.datang.bingxiang.ss; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; //加密解密 @Component public class DefaultPasswordEncoder implements PasswordEncoder{ //加密 @Override public String encode(CharSequence rawPassword) { return rawPassword.toString(); } //比较 @Override public boolean matches(CharSequence rawPassword, String encodedPassword) { // TODO Auto-generated method stub return encodedPassword.equals(rawPassword.toString()); } }
package com.datang.bingxiang.ss; import java.util.HashMap; import org.springframework.stereotype.Component; //模拟redis @Component public class RedisClient { private HashMap<String,Object> map = new HashMap(); public void add(String key,Object value) { map.put(key, value); } public void remove(String key) { map.remove(key); } public Object get(String key) { return map.get(key); } }
package com.datang.bingxiang.ss; import java.io.IOException; import java.io.PrintWriter; import java.util.HashMap; import javax.servlet.http.HttpServletResponse; import com.alibaba.fastjson.JSONObject; //返回值 public class ResponseUtil { public static void out(HttpServletResponse response) { HashMap<String, Object> r = new HashMap<>(); r.put("status", "200"); r.put("msg", "退出成功"); r.put("data", null); try { response.setCharacterEncoding("UTF-8"); response.setStatus(200); PrintWriter writer = response.getWriter(); writer.write(JSONObject.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } public static void authSucc(HttpServletResponse response, String token) { HashMap<String, Object> r = new HashMap<>(); r.put("status", "200"); r.put("msg", "认证成功"); r.put("data", token); try { response.setCharacterEncoding("UTF-8"); response.setStatus(200); PrintWriter writer = response.getWriter(); writer.write(JSONObject.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } public static void unAuth(HttpServletResponse response) { HashMap<String, Object> r = new HashMap<>(); r.put("status", "405"); r.put("msg", "未授权"); r.put("data", null); try { response.setCharacterEncoding("UTF-8"); response.setStatus(200); PrintWriter writer = response.getWriter(); writer.write(JSONObject.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } public static void authErr(HttpServletResponse response) { HashMap<String, Object> r = new HashMap<>(); r.put("status", "406"); r.put("msg", "认证失败"); r.put("data", null); try { response.setCharacterEncoding("UTF-8"); response.setStatus(200); PrintWriter writer = response.getWriter(); writer.write(JSONObject.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } public static void noPermiss(HttpServletResponse response) { HashMap<String, Object> r = new HashMap<>(); r.put("status", "407"); r.put("msg", "权限不足"); r.put("data", null); try { response.setCharacterEncoding("UTF-8"); response.setStatus(200); PrintWriter writer = response.getWriter(); writer.write(JSONObject.toJSONString(r)); writer.flush(); writer.close(); } catch (IOException e) { e.printStackTrace(); } } }
package com.datang.bingxiang.ss; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; //用户对象 public class SecurityUser implements UserDetails{ private String username; private String password; private Collection<GrantedAuthority> permissionValueList; public Collection<GrantedAuthority> getPermissionValueList() { return permissionValueList; } public void setPermissionValueList(Collection<GrantedAuthority> permissionValueList) { this.permissionValueList = permissionValueList; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } //----------------------------------- @Override public Collection<? extends GrantedAuthority> getAuthorities() { return permissionValueList; } @Override public String getPassword() { // TODO Auto-generated method stub return password; } @Override public String getUsername() { // TODO Auto-generated method stub return username; } @Override public boolean isAccountNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isAccountNonLocked() { // TODO Auto-generated method stub return true; } @Override public boolean isCredentialsNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { // TODO Auto-generated method stub return true; } }
package com.datang.bingxiang.ss; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("a") public String a() { return "a-----success"; } @GetMapping("b") public String b() { return "b-----success"; } @GetMapping("c") public String c() { return "c-----success"; } }
package com.datang.bingxiang.ss; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; //权限不足 public class TokenAccessDeniedHandler implements AccessDeniedHandler{ @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { ResponseUtil.noPermiss(response); } }
package com.datang.bingxiang.ss; import java.io.IOException; import java.util.List; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.tomcat.util.modeler.BaseAttributeFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; //授权过滤器 public class TokenAuthFilter extends BasicAuthenticationFilter { private TokenManager tokenManager; private RedisClient redis; public TokenAuthFilter(AuthenticationManager authenticationManager,TokenManager tokenManager,RedisClient redisClient) { super(authenticationManager); this.tokenManager = tokenManager; this.redis = redisClient; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String token = request.getHeader("token"); UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = null; if (token != null) { String username = tokenManager.getUserInfoFromToken(token); List<GrantedAuthority> permissionValueList = (List<GrantedAuthority>) redis.get(username); usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, token, permissionValueList); } if(usernamePasswordAuthenticationToken!=null) { SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken); } chain.doFilter(request, response); } }
package com.datang.bingxiang.ss; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; //认证过滤器 public class TokenLoginFileter extends UsernamePasswordAuthenticationFilter { private AuthenticationManager authenticationManager; private TokenManager tokenManager; private RedisClient redisClient; public TokenLoginFileter(AuthenticationManager authenticationManagerm,TokenManager tokenManager,RedisClient redisClient) { this.setPostOnly(false); this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST")); this.authenticationManager = authenticationManagerm; this.redisClient = redisClient; this.tokenManager = tokenManager; } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { String username = request.getParameter("username"); String password = request.getParameter("password"); return authenticationManager .authenticate(new UsernamePasswordAuthenticationToken(username, password, new ArrayList())); } @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { SecurityUser securityUser = (SecurityUser) authResult.getPrincipal(); String username = securityUser.getUsername(); String password = securityUser.getPassword(); Collection<GrantedAuthority> permissionValueList = securityUser.getPermissionValueList(); String token = tokenManager.createToken(username); redisClient.add(username, permissionValueList); ResponseUtil.authSucc(response, token); } @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { ResponseUtil.authErr(response); } }
package com.datang.bingxiang.ss; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutHandler; //退出登录 public class TokenLogoutHandler implements LogoutHandler { private TokenManager tokenManager; private RedisClient redis; TokenLogoutHandler(TokenManager tokenManager, RedisClient redis) { this.tokenManager = tokenManager; this.redis = redis; } @Override public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { String token = request.getHeader("token"); if (token != null) { String username = tokenManager.getUserInfoFromToken(token); redis.remove(username); ResponseUtil.out(response); } else { ResponseUtil.unAuth(response); } } }
package com.datang.bingxiang.ss; import java.util.Date; import org.springframework.stereotype.Component; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; //token @Component public class TokenManager { //创建token public String createToken(String username) { String secret = "1111"; String token = Jwts.builder().setHeaderParam("h1", "v1")// head .setHeaderParam("h2", "v2")// head .claim("userName", username)// body-内容 .claim("22222", "222222222")// body-内容 .setIssuer("顶风少年")// body-签发者 .setSubject("全体客户")// body-面向用户 .setAudience("接收人xxx")// body-接收者 .setIssuedAt(new Date())// body-签发时间 .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))// body-过期时间 .setNotBefore(new Date(System.currentTimeMillis() + 100))// body-不能再这个时间之前访问 .signWith(SignatureAlgorithm.HS256, secret)// 对head和body进行签名 .compact(); return token; } //获取用户名 public String getUserInfoFromToken(String token) { Jws<Claims> claimsJws = Jwts.parser().setSigningKey("1111").parseClaimsJws(token); return (String) claimsJws.getBody().get("userName"); } }
package com.datang.bingxiang.ss; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; 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.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; @Configuration public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsServiceImpl; @Autowired private TokenManager tokenManager; @Autowired private RedisClient redisClient; @Override protected void configure(HttpSecurity http) throws Exception { //禁用session http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); http.exceptionHandling() .authenticationEntryPoint(new UnauthEntryPoint())// 未授权 .accessDeniedHandler(new TokenAccessDeniedHandler())//权限不足 .and().csrf().disable() .authorizeRequests() .antMatchers("/b").hasAnyAuthority("m1") .antMatchers("/c").hasAnyAuthority("m3") .anyRequest().authenticated() .and() .logout().logoutUrl("/out")// 退出路径 .addLogoutHandler(new TokenLogoutHandler(tokenManager, redisClient)) .and() .addFilter(new TokenLoginFileter(authenticationManager(), tokenManager, redisClient)) .addFilter(new TokenAuthFilter(authenticationManager(), tokenManager, redisClient)); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsServiceImpl).passwordEncoder(new DefaultPasswordEncoder()); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/a"); } }
package com.datang.bingxiang.ss; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; //未授权 public class UnauthEntryPoint implements AuthenticationEntryPoint{ @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { ResponseUtil.unAuth(response); } }
package com.datang.bingxiang.ss; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; 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; //查询用户和权限 @Service public class UserDetailsServiceImpl implements UserDetailsService { HashMap<String, String> userMap = new HashMap<>(); HashMap<String, List<String>> permissMap = new HashMap<>(); public UserDetailsServiceImpl() { userMap.put("bbb", "bbb"); userMap.put("ccc", "ccc"); permissMap.put("bbb", Arrays.asList("m1", "m2")); permissMap.put("ccc", Arrays.asList("m3", "m4")); } @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { String password = userMap.get(username); if (password == null) { throw new UsernameNotFoundException("用户不存在"); } SecurityUser user = new SecurityUser(); user.setUsername(username); user.setPassword(password); List<String> permissionValueList = permissMap.get(username); if(permissionValueList!=null) { Collection<GrantedAuthority> authorities = new ArrayList<>(); for(String permissionValue:permissionValueList) { SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue); authorities.add(authority); } user.setPermissionValueList(authorities); } return user; } }