上目录结构
//权限管理模块 // 1. 创建一个权限管理的子模块 //2. 引入相关依赖 // <dependencies> //<!-- 自定义的模块 安全框架 security--> // <dependency> // <groupId>com.schoolWeb</groupId> // <artifactId>spring_security</artifactId> // <version>0.0.1-SNAPSHOT</version> // </dependency> // <dependency> // <groupId>com.alibaba</groupId> // <artifactId>fastjson</artifactId> // </dependency> // </dependencies> //3. 创建一个 权限管理的模块 编写相对应的权限代码 代码比较固定 分享到git 上了 //主要是 菜单管理 角色管理 分配权限 等常用功能 //4. 创建一个 spring_security模块 放在了 common模块里了 他是公共的 代码比较固定 分享到git 上了 // Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。提供了完善的认证机制和方法级的授权功能 // 本质就是过滤器 filter // 用于 用户认证 和用户授权 两部分 // 如果是基于Session 那么 Spring Security 会对cookie里的sessionid进行解析认证 // 如果是token 则会解析token 然后将当前请求加入到Spring Security 管理的权限信息里去 // 这个玩意 帮我们 取值 放值 帮我们 管理 token 或者 session 不需要我们 自己再去具体实现 // 如果系统的模块众多 每个模块都需要认证 用户根据用户密码进行认证 然后获取一系列的权限 并已用户名为key // 权限为value的形式存入redis里 根据用户的header头部里的token, Spring Security 解析token 这样判断是否有请求权限 //5. 引入spring_security 的相关依赖 // <dependencies> //<!-- 自定义的工具类--> // <dependency> // <groupId>com.schoolWeb</groupId> // <artifactId>common_utils</artifactId> // <version>0.0.1-SNAPSHOT</version> // </dependency> // <!-- Spring Security依赖 --> // <dependency> // <groupId>org.springframework.boot</groupId> // <artifactId>spring-boot-starter-security</artifactId> // </dependency> // // <dependency> // <groupId>io.jsonwebtoken</groupId> // <artifactId>jjwt</artifactId> // </dependency> // </dependencies> //6. 整合 spring security 框架 具体实现类 //7. 需要一个md5 和ResponseUtil 工具类 md5自行查找
public class ResponseUtil { public static void out(HttpServletResponse response, R r) { ObjectMapper mapper = new ObjectMapper(); response.setStatus(HttpStatus.OK.value()); response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); try { mapper.writeValue(response.getWriter(), r); } catch (IOException e) { e.printStackTrace(); } } }
//8. 需要配置核心配置类的退出地址 TokenWebSecurityConfig.java
@Configuration @EnableWebSecurity //开启权限控制 @EnableGlobalMethodSecurity(prePostEnabled = true) public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter { private UserDetailsService userDetailsService; // 自定义查询数据库 认证密码 private TokenManager tokenManager; //token 工具 private DefaultPasswordEncoder defaultPasswordEncoder; // 密码处理 private RedisTemplate redisTemplate; // redis 处理 @Autowired public TokenWebSecurityConfig(UserDetailsService userDetailsService, DefaultPasswordEncoder defaultPasswordEncoder, TokenManager tokenManager, RedisTemplate redisTemplate) { this.userDetailsService = userDetailsService; this.defaultPasswordEncoder = defaultPasswordEncoder; this.tokenManager = tokenManager; this.redisTemplate = redisTemplate; } /** * 配置设置 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http.exceptionHandling() .authenticationEntryPoint(new UnauthorizedEntryPoint()) .and().csrf().disable() .authorizeRequests() .anyRequest().authenticated() .and().logout() .logoutUrl("/admin/acl/index/logout") // 设置退出地址 可随意设置 .addLogoutHandler(new TokenLogoutHandler(tokenManager,redisTemplate)).and() .addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate)) .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate)).httpBasic(); } /** * 配置哪些请求不拦截 这个注意一下 要不 登录退出路径 有可能报错 404 * @param web * @throws Exception */ @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/api/**", "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**" ); // web.ignoring().antMatchers("/*/**" // ); } /** * 密码处理 * @param auth * @throws Exception */ @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder); }
//9. 实现 security提供的UserDetails 接口 SecurityUser.java
package com.school.security.entity; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.util.StringUtils; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * <p> * 安全认证用户详情信息 * </p> * 相关实体类 * @author qy * @since 2019-11-08 */ @Data @Slf4j public class SecurityUser implements UserDetails { //当前登录用户 private transient User currentUserInfo; //当前权限 private List<String> permissionValueList; public SecurityUser() { } public SecurityUser(User user) { if (user != null) { this.currentUserInfo = user; } } @Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<GrantedAuthority> authorities = new ArrayList<>(); for(String permissionValue : permissionValueList) { if(StringUtils.isEmpty(permissionValue)) continue; SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue); authorities.add(authority); } return authorities; } @Override public String getPassword() { return currentUserInfo.getPassword(); } @Override public String getUsername() { return currentUserInfo.getUsername(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
//10. 登录校验认证过滤器 配置登录地址 TokenLoginFilter.java
/**
* <p>
* 登录过滤器,继承UsernamePasswordAuthenticationFilter,对用户名密码进行登录校验
* </p>
* 认证过滤器
* @author qy
* @since 2019-11-08
*/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private TokenManager tokenManager;
private RedisTemplate redisTemplate;
public TokenLoginFilter(AuthenticationManager authenticationManager, TokenManager tokenManager, RedisTemplate redisTemplate) {
this.authenticationManager = authenticationManager;
this.tokenManager = tokenManager;
this.redisTemplate = redisTemplate;
this.setPostOnly(false);
//这是登录地址 这个可以随便配置
this.setRequiresAuthenticationRequestMatcher(
new AntPathRequestMatcher("/admin/acl/login","POST"));
}
//得到 用户密码
@Override
public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
throws AuthenticationException {
try {
User user = new ObjectMapper().readValue(req.getInputStream(), User.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 登录成功 执行这个
* @param req
* @param res
* @param chain
* @param auth
* @throws IOException
* @throws ServletException
*/
@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
Authentication auth) throws IOException, ServletException {
SecurityUser user = (SecurityUser) auth.getPrincipal();
//生成token 值
String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
//根据用户名 把需要的 权限 放到 redis里
redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());
ResponseUtil.out(res, R.ok().data("token", token));
}
/**
* 登录失败 执行这个
* @param request
* @param response
* @param e
* @throws IOException
* @throws ServletException
*/
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException e) throws IOException, ServletException {
ResponseUtil.out(response, R.error());
}
}
//11. 授权过滤器 //12. 配置好 spring security 框架后 把这个 模块引入到某个的模块下( 就是步骤2 那个依赖) // 比如 你 创建的 权限管理模块(acl) 这个模块下 都是权限授权和配置的操作 // 就可以引入到这个模块下 在这个模块具体使用spring security 下的功能 //13. 需要创建一个查询登录和用户权限的实现类 这个类 需要实现 spring security 下的 UserDetailsService 的接口 // 具体实现查询验证 用户登录 得到数据 // 注: 使用这种框架 思想为 :面向接口发开 或者 面向 spring security 开发 // 帮我们 实现了 验证 和授权登录 我们只需要 修改配置文件和 查询数据库数据 验证成功就行了
@Service("userDetailsService") public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserService userService; @Autowired private PermissionService permissionService; /*** * 根据账号获取用户信息 * @param username: * @return: org.springframework.security.core.userdetails.UserDetails */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 从数据库中取出用户信息 User user = userService.selectByUsername(username); // 判断用户是否存在 if (null == user){ //throw new UsernameNotFoundException("用户名不存在!"); } // 返回UserDetails实现类 com.school.security.entity.User curUser = new com.school.security.entity.User(); BeanUtils.copyProperties(user,curUser); //获取权限 List<String> authorities = permissionService.selectPermissionValueByUserId(user.getId()); SecurityUser securityUser = new SecurityUser(curUser); securityUser.setPermissionValueList(authorities); return securityUser; } }
// 使用了这个security 框架 实现登录后 自己开发的 登录 就无需再用了
github地址
javaUtils/spring_security at main · Json870422471/javaUtils · GitHub