使用场景
用户访问不同路径需要不同的权限。
1.实现用户对应权限
package com.mt.config;
import com.mt.service.impl.AuthPathServiceImpl;
import com.mt.service.impl.UserDetailsServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.method.configuration.EnableGlobalMethodSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;
import java.util.Map;
/**
* 项目安全访问权限配置
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private AuthPathServiceImpl authPathService;
//swagger地址不被拦截配置
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/swagger-ui.html")
.antMatchers("/v2/**")
.antMatchers("/swagger-resources/**");
}
//自定义权限加载
@Override
protected void configure(HttpSecurity http) throws Exception {
logger.info("自定义权限配置加载..");
//获取对应权限的正则匹配值 例如:/admin/\w*
Map<String,String> regex = authPathService.getRoleAuthPath();
http
.authorizeRequests().regexMatchers(regex.get("4")==null?"":regex.get("4")).hasAnyRole("USER","ADMIN","COMMON","ROOT")
.and()
.authorizeRequests().regexMatchers(regex.get("3")==null?"":regex.get("3")).hasAnyRole("USER","ADMIN","ROOT")
.and()
.authorizeRequests().regexMatchers(regex.get("2")==null?"":regex.get("2")).hasAnyRole("ADMIN","ROOT")
.and()
.authorizeRequests().regexMatchers(regex.get("1")==null?"":regex.get("1")).hasRole("ROOT")
.and()
.authorizeRequests()
.antMatchers("/").permitAll()
.and()
.httpBasic()
.and()
.logout()
.permitAll();
http.csrf().disable(); //取消csrf防护
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//basic auth 基本权限认证,也可注释
auth
.inMemoryAuthentication()
.passwordEncoder(new BCryptPasswordEncoder()).withUser("admin").password(new BCryptPasswordEncoder().encode("admin")).roles("ADMIN")
.and()
.passwordEncoder(new BCryptPasswordEncoder()).withUser("user").password(new BCryptPasswordEncoder().encode("user")).roles("USER")
.and()
.passwordEncoder(new BCryptPasswordEncoder()).withUser("common").password(new BCryptPasswordEncoder().encode("common")).roles("COMMON");
// 数据库账号密码认证
// 密码需要设置编码器
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
}
}
package com.mt.service.impl;
import com.mt.bean.Authority;
import org.springframework.beans.factory.annotation.Autowired;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* 用户权限识别与认证
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserServiceImpl userService;
@Autowired
private AuthorityServiceImpl authorityService;
/**
* 通过业务方法获取用户权限信息
*/
@Override
public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
//获取用户信息
com.mt.bean.User user=userService.userGetByPhone(id);
//获取用户权限
List<Authority> authorities = authorityService.getCustomerAuthority(String.valueOf(user.getUserId()));
// 对用户权限进行封装
List<SimpleGrantedAuthority> list = authorities.stream()
.map(authority -> new SimpleGrantedAuthority(authority.getAuthority()))
.collect(Collectors.toList());
// 返回封装的UserDetails用户详情类
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
return new User(String.valueOf(user.getUserId()), encoder.encode(user.getUserPwd()), list);
}
}
package com.mt.bean;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.persistence.Table;
/**
* 用户权限
*/
@Data
@Accessors(chain=true)
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Table(name = "authority_user")
public class AuthorityUser {
private String id;
private Integer userId;
private String authorityId ;
private String valid;
}
package com.mt.bean;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.persistence.Table;
/**
* 权限角色表
*/
@Data
@Accessors(chain=true)
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Table(name = "authority")
public class Authority {
private String id;
private String authority ;
private String valid;
}
package com.mt.bean;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Id;
import javax.persistence.Table;
import java.io.Serializable;
/**
* 用户表
*/
@Data
@Accessors(chain=true)
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Table(name="user")
public class User implements Serializable {
private Integer userId;
private String userName;
private String userPhone;
private int userAge;
private String userSex;
private String userPwd;
}
package com.mt.service.impl;
import com.mt.bean.Authority;
import com.mt.bean.AuthorityUser;
import com.mt.mapper.AuthorityMapper;
import com.mt.mapper.AuthorityUserMapper;
import com.mt.service.AuthorityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 权限用户
*/
@Service
public class AuthorityServiceImpl implements AuthorityService {
@Autowired
private AuthorityMapper authorityMapper;
@Autowired
private AuthorityUserMapper authorityUserMapper;
@Override
public List<Authority> getCustomerAuthority(String id) {
List<AuthorityUser> authUerRole = authorityUserMapper.getAuthUserRole(id);
List<Authority> authorities=new ArrayList<>();
authUerRole.forEach(authorityUser -> {
List<Authority> customerAuthority = authorityMapper.getCustomerAuthority(authorityUser.getAuthorityId());
authorities.addAll(customerAuthority);
});
return authorities;
}
}
2.实现不同的路径需要不同权限
package com.mt.bean;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.persistence.Table;
import java.io.Serializable;
/**
* 权限路径表
*/
@Data
@Accessors(chain=true)
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@Table(name="auth_path")
public class AuthPath {
private Integer id;
private String authPath;
private String valid;
private String authorityId;
}
package com.mt.service.impl;
import com.mt.bean.AuthPath;
import com.mt.mapper.AuthPathMapper;
import com.mt.service.AuthPathService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
/**
* 权限处理
*/
@Service
public class AuthPathServiceImpl implements AuthPathService {
@Autowired
private AuthPathMapper authPathMapper;
@Override
public Map<String,String> getRoleAuthPath() {
//获取所有权限路径,将其安装权限类型分组,再根据key排序
List<AuthPath> authPaths = authPathMapper.selectAll();
//过滤出生效的数据
authPaths=authPaths.stream().filter(authPath -> "0".equals(authPath.getValid())).collect(Collectors.toList());
//将其按照id成map
Map<String, List<AuthPath>> authPathMap = authPaths.stream().collect(Collectors.groupingBy(AuthPath::getAuthorityId));
Map<String, List<AuthPath>> result = new LinkedHashMap<>(authPathMap.size());
//将其按照id排序
authPathMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).forEachOrdered(e -> result.put(e.getKey(), e.getValue()));
//将获取到的多个组合成一个正则,加上()即可
Map<String,String> stringBuilderMap= new HashMap<>();
result.forEach((k,v)->{
StringBuilder str = new StringBuilder();
for (AuthPath authPath : v) {
if(!"".equals(str.toString())){
str.append("|");
}
str.append("(").append(authPath.getAuthPath()).append(")");
}
stringBuilderMap.put(k,str.toString());
});
return stringBuilderMap;
}
}
3.实现用户登录刷新权限
@Autowired
private SecurityAuthUtil securityAuthUtil;
@ApiOperation("用户登录")
@PostMapping("/login")
public User userLogin(HttpServletRequest request,String phone, String password, HttpSession session,HttpServletResponse response) throws Exception {
User user = userService.userLogin(phone, password);
if (user != null) {
//在session中存放security context,方便同一个session中控制用户的其他操作
session.setAttribute("SPRING_SECURITY_CONTEXT",securityAuthUtil.auth(request,user.getUserPhone()));
session.setAttribute("user", user);
LOGGER.info(user.getUserName() + "登录成功.." + "账号:" + user.getUserPhone() + " 密码:" + user.getUserPwd());
}
return user;
}
package com.mt.util;
import com.mt.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
/**
*
* 登录权限管理工具
*/
@Component
public class SecurityAuthUtil {
@Autowired
private UserDetailsServiceImpl userDetailsService;
public Object auth(HttpServletRequest request,String id){
//根据用户名username加载userDetails
UserDetails userDetails = this.userDetailsService.loadUserByUsername(id);
//根据userDetails构建新的Authentication,这里使用了
//PreAuthenticatedAuthenticationToken当然可以用其他token,如UsernamePasswordAuthenticationToken
PreAuthenticatedAuthenticationToken authentication =
new PreAuthenticatedAuthenticationToken(userDetails, userDetails.getPassword(),userDetails.getAuthorities());
//设置authentication中details
authentication.setDetails(new WebAuthenticationDetails(request));
//存放authentication到SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(authentication);
return SecurityContextHolder.getContext();
}
public void cancelAuth(){
SecurityContextHolder.clearContext();
}
}
4.用户登出删除权限
@Autowired
private SecurityAuthUtil securityAuthUtil;
@ApiOperation("用户登出")
@GetMapping("/loginOut")
public int userLoginOut(HttpSession session) {
User user = (User) session.getAttribute("user");
if (session.getAttribute("user") != null) {
session.removeAttribute("user");
session.invalidate();
securityAuthUtil.cancelAuth();
LOGGER.info(user.getUserName()+"登出成功..");
return 1;
} else {
return 0;
}
}