SpringBoot整合SpringSecurity(内含代码)
SpringBoot整合SpringSecurity详细
我的资源已经上传整个项目代码和sql 需要的可以下载。
1.创建SpringBoot项目并导入Pom.xml文件
<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<!-- thymeleaf模板插件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--暴露各种指标 客户端post /refresh 方式刷新支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 客户端依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- jcaptcha 验证码 -->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<!-- 阿里巴巴druid数据源 -->
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- <version>5.1.6</version> -->
<version>5.1.40</version>
</dependency>
<!-- mybatis 分页 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<!-- reids -->
<dependency>
<groupId>org.springframework.boot</groupId>
<!-- <artifactId>spring-boot-starter-redis</artifactId> -->
<artifactId>spring-boot-starter-data-redis</artifactId>
<!-- <version>1.4.3.RELEASE</version> -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- HTMl解析工具 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
</dependency>
<!-- <dependency> <groupId>com.alibaba</groupId> <artifactId>fastJson</artifactId>
<version>1.2.17</version> </dependency> -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<!-- restful开发规范依赖 -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<!-- 配置spring boot热部署 -->
<!-- optional=true,依赖不会传递,该项目依赖devtools;之后依赖myboot项目的项目如果想要使用devtools,需要重新引入 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
2.导入config配置类
- AuthenticationAccessDeniedHandler
@Component
public class AuthenticationAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse resp, AccessDeniedException e)
throws IOException {
resp.setStatus(HttpServletResponse.SC_FORBIDDEN);
resp.setContentType("application/json;charset=UTF-8");
PrintWriter out = resp.getWriter();
System.out.println("----------------------" + 2222);
out.flush();
out.close();
}
}
- CustomerUserDetails
public class CustomerUserDetails implements UserDetails {
private static final long serialVersionUID = 1L;
private AccountsEntity account = null;
// 存放权限的集合
private Collection<? extends GrantedAuthority> authorities = null;
private boolean accountNonExpired = false;
private boolean accountNonLocked = false;
private boolean credentialsNonExpired = false;
private boolean enabled = false;
public CustomerUserDetails(AccountsEntity account, Collection<? extends GrantedAuthority> authorities) {
this(account, true, true, true, true, authorities);
}
public CustomerUserDetails(AccountsEntity account, boolean enabled, boolean accountNonExpired,
boolean credentialsNonExpired, boolean accountNonLocked,
Collection<? extends GrantedAuthority> authorities) {
if (account.getUsername() != null && !"".equals(account.getUsername()) && account.getPassword() != null) {
this.account = account;
this.enabled = enabled;
this.accountNonExpired = accountNonExpired;
this.credentialsNonExpired = credentialsNonExpired;
this.accountNonLocked = accountNonLocked;
this.authorities = authorities;
} else {
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
}
}
public AccountsEntity getAccountsEntity() {
return account;
}
public void setAccountsEntity(AccountsEntity account) {
this.account = account;
}
public boolean equals(Object rhs) {
return rhs instanceof CustomerUserDetails
&& this.getUsername().equals(((CustomerUserDetails) rhs).getUsername());
}
public int hashCode() {
return this.getUsername().hashCode();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public String getPassword() {
return this.account.getPassword();
}
@Override
public String getUsername() {
return this.account.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return this.accountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return this.accountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return this.credentialsNonExpired;
}
@Override
public boolean isEnabled() {
return this.enabled;
}
}
- CustomMetadataSource
@Component
public class CustomMetadataSource implements FilterInvocationSecurityMetadataSource {
@Autowired
private PermissionsMapper permissionsMapper;
// resourceMap及为key-url,value-Collection<ConfigAttribute>,资源权限对应Map
private static Map<String, Collection<ConfigAttribute>> resourceMap = null;
public void MyInvocationSecurityMetadataSourceService(PermissionsMapper permissionsMapper) {
this.permissionsMapper = permissionsMapper;
System.out.println("加载MyInvocationSecurityMetadataSourceService..." + permissionsMapper);
loadResourceDefine();
}
// 加载所有资源与权限的关系
private void loadResourceDefine() {
if (resourceMap == null) {
resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
Collection<ConfigAttribute> array;
ConfigAttribute cfg = null;
List<PermissionsEntity> permissions = permissionsMapper.getAllPermission();
System.out.println("permissions的size" + permissions.size());
// 加载资源对应的权限
for (PermissionsEntity permission : permissions) {
System.out.println("permission的对应的url信息:" + permission.getUrl());
array = new ArrayList<>();
for (RolesEntity role : permission.getRoles()) {
cfg = new SecurityConfig(role.getRolename());
array.add(cfg);
}
System.out.println("权限=" + array);
resourceMap.put(permission.getUrl(), array);
}
}
}
// 由资源路径获得权限
// object为请求的资源路径
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
// object是一个URL,被用户请求的url
String requestUrl = ((FilterInvocation) object).getRequestUrl();
System.out.println("requestUrl is " + requestUrl);
int firstQuestionMarkIndex = requestUrl.indexOf("?");
// 如果请求的资源路径有?后面的参数,则将?后面的切掉,以免拒绝访问
if (firstQuestionMarkIndex != -1) {
requestUrl = requestUrl.substring(0, firstQuestionMarkIndex);
}
if (resourceMap == null) {
loadResourceDefine();
}
//
Iterator<String> ite = resourceMap.keySet().iterator();
// 根据资源路径获得其所需的权限
while (ite.hasNext()) {
String resURL = ite.next();
if (resURL.equals(requestUrl)) {
return resourceMap.get(resURL);
}
}
return SecurityConfig.createList("ROLE_LOGIN");
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return FilterInvocation.class.isAssignableFrom(aClass);
}
}
- UrlAccessDecisionManager
@Component
public class UrlAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication auth, Object o, Collection<ConfigAttribute> cas) {
System.out.println("进入权限判断--------");
Iterator<ConfigAttribute> iterator = cas.iterator();
while (iterator.hasNext()) {
ConfigAttribute ca = iterator.next();
// 当前请求需要的权限 不能吧
String needRole = ca.getAttribute();
System.out.println("当前请求需要的权限" + needRole);
if ("ROLE_LOGIN".equals(needRole)) {
if (auth instanceof AnonymousAuthenticationToken) {
throw new BadCredentialsException("未登录");
} else
return;
}
// 当前用户所具有的权限
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
for (GrantedAuthority authority : authorities) {
System.out.println("当前用户所具有的权限" + authority.getAuthority());
if (authority.getAuthority().equals(needRole)) {
System.out.println("具备权限,匹配成功");
return;
}
}
}
throw new AccessDeniedException("权限不足!");
}
@Override
public boolean supports(ConfigAttribute configAttribute) {
return true;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
- WebMvcConfig
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new DateConverter());
}
@Bean
public ExecutorService executorService() {
return Executors.newCachedThreadPool();
}
}
- WebSecurityConfig
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
AccountsService accountService;
@Autowired
CustomMetadataSource metadataSource;
@Autowired
UrlAccessDecisionManager urlAccessDecisionManager;
@Autowired
AuthenticationAccessDeniedHandler deniedHandler;
@Resource
private DataSource dataSource;
/*
* public static void main(String[] args) { BCryptPasswordEncoder
* passwordEncoder = new BCryptPasswordEncoder(); String newpass =
* passwordEncoder.encode("123456"); System.out.println(newpass); }
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(accountService).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/index.html", "/static/**", "/login_p", "/favicon.ico", "/login.html");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O o) {
System.out.println("开始验证++++++++");
o.setSecurityMetadataSource(metadataSource);
o.setAccessDecisionManager(urlAccessDecisionManager);
return o;
}
}).and().formLogin().loginPage("/login_p").loginProcessingUrl("/login").usernameParameter("username")
.passwordParameter("password").failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
AuthenticationException e) throws IOException {
resp.setContentType("application/json;charset=utf-8");
ProjectError projectError = null;
if (e instanceof BadCredentialsException || e instanceof UsernameNotFoundException) {
projectError = ProjectError.failure(StatusCode.USER_LOGIN_ERROR);
} else if (e instanceof LockedException) {
projectError = ProjectError.failure(StatusCode.USER_ACCOUNT_LOCKED);
} else if (e instanceof CredentialsExpiredException) {
projectError = ProjectError.failure(StatusCode.PASSWRD_HAS_OUTTIME);
} else if (e instanceof AccountExpiredException) {
projectError = ProjectError.failure(StatusCode.USER_HAS_OUTTIME);
} else if (e instanceof DisabledException) {
projectError = ProjectError.failure(StatusCode.USER_ACCOUNT_FORBIDDEN);
} else {
projectError = ProjectError.failure(StatusCode.USER_LOGIN_FAILED);
}
resp.setStatus(401);
ObjectMapper om = new ObjectMapper();
PrintWriter out = resp.getWriter();
out.write(om.writeValueAsString(projectError));
out.flush();
out.close();
}
}).successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,
Authentication auth) throws IOException {
resp.setContentType("application/json;charset=utf-8");
ResultSuccess success = new ResultSuccess();
success.setMsg("登录成功!");
success.setData(HrUtils.getCurrentHr());
ObjectMapper om = new ObjectMapper();
PrintWriter out = resp.getWriter();
out.write(om.writeValueAsString(success));
out.flush();
out.close();
}
}).permitAll().and().logout().deleteCookies("JSESSIONID").logoutUrl("/logout")
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp,
Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
ResultSuccess success = new ResultSuccess();
success.setMsg("注销成功!");
ObjectMapper om = new ObjectMapper();
PrintWriter out = resp.getWriter();
out.write(om.writeValueAsString(success));
out.flush();
out.close();
}
}).permitAll().and().rememberMe().tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(1209600).and().csrf().disable().exceptionHandling()
.accessDeniedHandler(deniedHandler);
http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(false).expiredUrl("/login?expired");
}
// 如果采用持久化 token 的方法则需要指定保存token的方法
@Bean
public PersistentTokenRepository persistentTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource);
return db;
}
}
3.具体逻辑代码
- Controller:这里只是登录过后判断权限路劲时候访问的(这里跟登录没关系)
@Mapper
public interface AccountsMapper {
AccountsEntity loadUserByUsername(@Param("username") String username);
List<RolesEntity> getRolesByUserId(@Param("id") Long id);
List<RolesEntity> getRolesByUserName(@Param("username") String username);
CustomerUserDetails loadUserByPassword(@Param("encode") String encode);
void updatePassword(@Param("username") String username, @Param("newpassword") String newpassword);
void resetPassword(@Param("username") String username, @Param("resetPassword") String resetPassword);
}
public interface PermissionsMapper {
List<PermissionsEntity> getAllPermission();
public List<PermissionsEntity> findPermissionsAll();
public int addPermissions(@Param("permissions") PermissionsEntity permissionsEntity);
public int updatePermissionsById(@Param("permissionsId") long permissionsId, @Param("permissions") PermissionsEntity permissionsEntity);
public int delPermissionsById(@Param("permissionsId") long permissionsId);
List<PermissionsEntity> findPermissionsAll2();
List<PermissionsEntity> findPermissionsAll3();
List<PermissionsEntity> findPermissionsAllByparentId1();
List<PermissionsEntity> findPermissionsAllByparentId2();
}
public interface RolesMapper {
List<RolesEntity> roles();
List<RolesEntity> getRolesByUrl(String url);
public int addRole(@Param("roles") RolesEntity rolesEntity);
public int updateRoleByRoleId(@Param("roleId") long roleId, @Param("roles") RolesEntity rolesEntity);
public int delRoleByRoleId(@Param("roleId") long roleId);
public List<RolesEntity> findRolesAll();
public List<RolesEntity> findRoles();
public int addRelations(@Param("rolePermRelation") List<String> rolePermRelationList, @Param("roleId") long roleId);
public int delRelations(@Param("roleId") long roleId, @Param("deletePerID") long deletePerID);
}
@Table(name = "user_accounts")
public class AccountsEntity implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String uuid; // 由用户名+手机号+邮箱生成的登录账号
private String username; // 用户名
private String phone; // 电话
private String email; // 邮件
private String password; // 密码
private String salt; // 盐(前端不需要管)
private int locked = 0; // 是否锁定(0表示未锁定,可用,1表示不可用)
private long companyId; // 公司id
private boolean rememberMe; // 记住我
private Date createTime; // 创建时间
private Date modifyTime; // 修改时间
private List<RolesEntity> roles;
public Boolean isLocked() {
return locked != 0;
}
public long getId() {
return id;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public boolean isRememberMe() {
return rememberMe;
}
public void setRememberMe(boolean rememberMe) {
this.rememberMe = rememberMe;
}
public void setId(long id) {
this.id = id;
}
public long getCompanyId() {
return companyId;
}
public void setCompanyId(long companyId) {
this.companyId = companyId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
public void setLocked(int locked) {
this.locked = locked;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getModifyTime() {
return modifyTime;
}
public void setModifyTime(Date modifyTime) {
this.modifyTime = modifyTime;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<RolesEntity> getRoles() {
return roles;
}
public void setRoles(List<RolesEntity> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "AccountsEntity [id=" + id + ", uuid=" + uuid + ", phone=" + phone + ", email=" + email + ", password="
+ password + ", salt=" + salt + ", locked=" + locked + ", rememberMe=" + rememberMe + ", createTime="
+ createTime + ", modifyTime=" + modifyTime + "]";
}
}
@Data
@Table(name = "t_hobby")
public class Hobby {
private Integer id;
private String hname;
@Override
public String toString() {
return "Hobby{" +
"id=" + id +
", hname='" + hname + '\'' +
'}';
}
}
public class PermissionsEntity implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String url; // 请求路径
private String describes;// 功能描述
private int locked; // 是否锁定
private Date createTime;// 创建时间
private Date modifyTime;// 修改时间
private List<RolesEntity> roles;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDescribes() {
return describes;
}
public void setDescribes(String describes) {
this.describes = describes;
}
public int getLocked() {
return locked;
}
public void setLocked(int locked) {
this.locked = locked;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getModifyTime() {
return modifyTime;
}
public void setModifyTime(Date modifyTime) {
this.modifyTime = modifyTime;
}
public List<RolesEntity> getRoles() {
return roles;
}
public void setRoles(List<RolesEntity> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "PermissionsEntity [id=" + id + ", url=" + url + ", describes=" + describes + ", locked=" + locked
+ ", createTime=" + createTime + ", modifyTime=" + modifyTime + "]";
}
}
public class RolesEntity implements Serializable {
private static final long serialVersionUID = 1L;
private long id;
private String rolename;
private String describes;
private int locked;
private int rolesType; // 0 admin 1默认 2自定义
private long companyId;
private Date createTime;
private Date modifyTime;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRolename() {
return rolename;
}
public void setRolename(String rolename) {
this.rolename = rolename;
}
public long getCompanyId() {
return companyId;
}
public void setCompanyId(long companyId) {
this.companyId = companyId;
}
public String getDescribes() {
return describes;
}
public void setDescribes(String describes) {
this.describes = describes;
}
public int getLocked() {
return locked;
}
public void setLocked(int locked) {
this.locked = locked;
}
public int getRolesType() {
return rolesType;
}
public void setRolesType(int rolesType) {
this.rolesType = rolesType;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getModifyTime() {
return modifyTime;
}
public void setModifyTime(Date modifyTime) {
this.modifyTime = modifyTime;
}
@Override
public String toString() {
return "RolesEntity [id=" + id + ", rolename=" + rolename + ", describes=" + describes + ", locked=" + locked
+ ", rolesType=" + rolesType + ", companyId=" + companyId + ", createTime=" + createTime
+ ", modifyTime=" + modifyTime + "]";
}
}
@Service
@Transactional
public class AccountsServiceImpl implements AccountsService {
@Autowired
AccountsMapper accountsMapper;
@Override
public CustomerUserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AccountsEntity account = accountsMapper.loadUserByUsername(username);
if (account == null)
throw new UsernameNotFoundException("Username not found");
System.out.println("当前需要认证的登录名:" + account.getUsername());
List<GrantedAuthority> authorities = new ArrayList<>();
List<RolesEntity> rolelist = account.getRoles();
if (rolelist != null) {
for (RolesEntity role : rolelist) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getRolename());
// 此处将权限信息添加到 GrantedAuthority
// 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。
authorities.add(grantedAuthority);
}
}
return new CustomerUserDetails(account, authorities);
}
@Override
public void updatePassword(String username, String newpassword) {
accountsMapper.updatePassword(username,newpassword);
}
/**
*
* 根据密码查找用户
* @param encode
* @return
*/
@Override
public CustomerUserDetails loadUserByPassword(String encode) {
CustomerUserDetails customerUserDetails = accountsMapper.loadUserByPassword(encode);
return customerUserDetails;
}
/**
* 重置密码 密码为123456
* @param username
* @param resetPassword 密码
*/
@Override
public void resetPassword(String username, String resetPassword) {
accountsMapper.resetPassword(username,resetPassword);
}
}
@Service
public interface AccountsService extends UserDetailsService {
public CustomerUserDetails loadUserByUsername(String username);
void updatePassword(String username, String newpassword);
CustomerUserDetails loadUserByPassword(String encode);
void resetPassword(String username, String resetPassword);
}
@Service
@Transactional
@CacheConfig(cacheNames = "menus_cache")
public class PermissionsService {
PermissionsMapper permissionsMapper;
// @Cacheable(key = "#root.methodName")
public List<PermissionsEntity> getAllPermission() {
return permissionsMapper.getAllPermission();
}
public List<PermissionsEntity> findPermissionsAll() {
// TODO Auto-generated method stub
return permissionsMapper.findPermissionsAll();
}
@Transactional
public boolean addPermissions(PermissionsEntity permissionsEntity) {
// TODO Auto-generated method stub
int result = permissionsMapper.addPermissions(permissionsEntity);
return result > 0;
}
@Transactional
public boolean updatePermissionsById(long permissionsId, PermissionsEntity permissionsEntity) {
// TODO Auto-generated method stub
int result = permissionsMapper.updatePermissionsById(permissionsId, permissionsEntity);
return result > 0;
}
public boolean delPermissionsById(long permissionsId) {
// TODO Auto-generated method stub
int result = permissionsMapper.delPermissionsById(permissionsId);
return result > 0;
}
public List<PermissionsEntity> findPermissionsAllByparentId1() {
return permissionsMapper.findPermissionsAllByparentId1();
}
public List<PermissionsEntity> findPermissionsAllByparentId2() {
return permissionsMapper.findPermissionsAllByparentId2();
}
}
@Service
@Transactional
public class RolesService{
@Autowired
RolesMapper roleMapper;
public List<RolesEntity> roles() {
return roleMapper.roles();
}
public List<RolesEntity> getRolesByUrl(String url) {
// TODO Auto-generated method stub
return roleMapper.getRolesByUrl(url);
}
public boolean delRelations(long roleId, long deletePerID) {
// TODO Auto-generated method stub
int result = roleMapper.delRelations(roleId, deletePerID);
return result > 0;
}
@Transactional
public boolean addRelations(List<String> rolePermRelationList, long roleId) {
// TODO Auto-generated method stub
int result = roleMapper.addRelations(rolePermRelationList, roleId);
return result > 0;
}
public List<RolesEntity> findRoles() {
// TODO Auto-generated method stub
return roleMapper.findRoles();
}
public List<RolesEntity> findRolesAll() {
// TODO Auto-generated method stub
return roleMapper.findRoles();
}
@Transactional
public boolean addRole(RolesEntity rolesEntity) {
System.out.println("------------>" + rolesEntity.toString());
int result = roleMapper.addRole(rolesEntity);
return result > 0;
}
@Transactional
public boolean updateRoleByRoleId(long roleId, RolesEntity rolesEntity) {
int result = roleMapper.updateRoleByRoleId(roleId, rolesEntity);
return result > 0;
}
public boolean delRoleByRoleId(long roleId) {
int result = roleMapper.delRoleByRoleId(roleId);
return result > 0;
}
}
public class DateConverter implements Converter<String,Date> {
private final SimpleDateFormat smf = new SimpleDateFormat("yyyyMMdd");
@Override
public Date convert(String s) {
if ("".equals(s) || null == s) {
return null;
}
try {
return smf.parse(s);
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
public class HrUtils {
public static CustomerUserDetails getCurrentHr() {
return (CustomerUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
public class ProjectError extends ResultError implements Serializable {
/**
* 请求的响应结果
*/
private static final long serialVersionUID = 1L;
private int code;// 自定义错误编码
private int httpCode; // http状态码
private String url; // 操作结果
private String msg;// 提示消息
public ProjectError() {
}
public static ProjectError failure(StatusCode StatusCode) {
ProjectError ProjectError = new ProjectError();
ProjectError.setStatusCode(StatusCode);
return ProjectError;
}
public static ProjectError failure(StatusCode StatusCode, Object data) {
ProjectError ProjectError = new ProjectError();
ProjectError.setStatusCode(StatusCode);
return ProjectError;
}
private void setStatusCode(StatusCode code) {
this.code = code.code();
this.httpCode = 500;
this.msg = code.message();
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public int getHttpCode() {
return httpCode;
}
public void setHttpCode(int httpCode) {
this.httpCode = httpCode;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
public class ResultError {
// private static final long serialVersionUID = 1L;
}
public class ResultSuccess {
private Integer code ;
private String referer; // 发送请求的地址
private String redirect; // 重定向的地址
private String msg; //
private Object data;
public ResultSuccess() {
super();
}
public ResultSuccess(Integer code, String msg) {
super();
this.code = code;
this.msg = msg;
}
public ResultSuccess(String msg, Object data) {
this.data = data;
}
public ResultSuccess(Integer code, String msg, Object data) {
super();
this.code = code;
this.msg = msg;
this.data = data;
}
public ResultSuccess(String msg) {
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getReferer() {
return referer;
}
public void setReferer(String referer) {
this.referer = referer;
}
public String getRedirect() {
return redirect;
}
public void setRedirect(String redirect) {
this.redirect = redirect;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
public enum StatusCode {
/* 成功状态码 */
SUCCESS(10000, true, "操作成功"), //
OTHER_EXCEPTION(0, false, "其他异常"), //
// NOT_FOUND_RESOURCE(404, false, "路径错误"), //
//
// INTERNAL_SERVER_ERROR(500, false, "服务器内部错误"), //
/* 参数错误 */
PARAM_IS_INVALID(10001, false, "参数无效"), //
PARAM_IS_BLANK(10002, false, "参数为空"), //
PARAM_TYPE_BIND_ERROR(10003, false, "参数类型错误"), //
PARAM_NOT_COMPLETE(10004, false, "参数缺失"), //
ID_NOT_EQUAL(10005, false, "信息ID异常"), //
PHONE_IS_ERROR(10006, false, "手机号错误"), //
PHONECAPTCHA_IS_ERROR(10007, false, "手机验证码错误"), //
CAPTCHA_IS_ERROR(10008, false, "验证码错误"), //
EMAIL_IS_ERROR(10009, false, "邮箱错误"), //
USER_INPUT_IS_BLANK(10010, false, "账号或密码为空"), //
NAME_OR_PASSWRD_IS_BLANK(10011, false, "联系人或密码为空"), //
PASSWRD_NOT_ALIKE(10012, false, "密码不一致"), //
PROTOCOL_NOT_READER(10013, false, "请先阅读并同意相关协议"), //
PASSWRD_IS_ERROR(10014, false, "原密码输入错误"), //
/* 用户错误 */
USER_NOT_LOGGED_IN(20001, false, "用户未登录或SESSION已过期"), //
USER_LOGIN_ERROR(20002, false, "账号不存在或密码错误"), //
USER_ACCOUNT_FORBIDDEN(20003, false, "账号已被禁用"), //
USER_NOT_EXIST(20004, false, "用户不存在"), //
LOGINNAME_HAS_EXISTED(20005, false, "用户名已被注册"), //
PHONE_HAS_EXISTED(20006, false, "手机号已经注册"), //
EMAIL_HAS_EXISTED(20007, false, "邮箱已经注册"), //
USER_INFO_ERROR(20008, false, "用户信息异常"), //
USER_LOGIN_FAILED(20009, false, "系统异常,请联系管理员"), //
PASSWRD_RESET_FAILED(20010, false, "密码重置失败"), //
PHONE_NOT_EXIST(20011, false, "手机号未注册"), //
PASSWRD_HAS_OUTTIME(20012, false, "密码已过期,请联系管理员"), USER_HAS_OUTTIME(20013, false,
"账户已过期,请联系管理员"), USER_ACCOUNT_LOCKED(20014, false, "账户被锁定,请联系管理员"),
/* 数据错误 */
RESULE_DATA_NONE(30001, false, "数据未找到"), //
DATA_IS_WRONG(30002, false, "数据有误"), //
DATA_ALREADY_EXISTED(30003, false, "数据已存在"), //
OPERATE_EXCEPTION(30004, false, "操作异常"), //
CAPTCHA_BUILD_FAILED(30005, false, "验证码生成失败"), //
PHONECAPTCHA_BUILD_FAILED(30006, false, "手机验证码发送失败"), //
ROLL_BACK_FAILED(30007, false, "数据回滚失败"), //
INIT_INFO_FAILED(30008, false, "信息初始化失败"), //
UPLOAD_FILE_FAILED(30009, false, "文件上传失败"), //
EXCEED_MAX_AMOUNT(30010, false, "文件数量超过上限"), //
EXCEED_MAX_SIZE(30011, false, "文件大小超过上限"), //
FILE_NOT_EXIST(30012, false, "文件不存在"), //
ORDER_STATUS_ERROR(30013, false, "工单状态异常"), //
WORD_EXCEED_MAX_SIZE(30014, false, "文字长度不符合规定"), //
CUSTOMER_DONT_DELETE(30015, false, "合作中的客户,不能删除"), //
SLA_DONT_OPERATION(30016, false, "使用中的SLA,不能编辑和删除"), //
/* 权限错误 */
PERMISSION_NO_ACCESS(40001, false, "无访问权限"), //
PERMISSION_NO_OPERATION(40002, false, "无操作权限"), //
SYSTEM_ERROR(99999, false, "系统异常");
private Integer code;
private boolean status;
private String message;
StatusCode(Integer code, boolean status, String message) {
this.code = code;
this.status = status;
this.message = message;
}
public Integer code() {
return this.code;
}
public boolean status() {
return this.status;
}
public String message() {
return this.message;
}
public static StatusCode getStatusCode(Integer code) {
for (StatusCode item : StatusCode.values()) {
if (item.code().equals(code)) {
return item;
}
}
return null;
}
public static String getMessage(String name) {
for (StatusCode item : StatusCode.values()) {
if (item.name().equals(name)) {
return item.message;
}
}
return name;
}
public static Integer getCode(String name) {
for (StatusCode item : StatusCode.values()) {
if (item.name().equals(name)) {
return item.code;
}
}
return null;
}
@Override
public String toString() {
return this.name();
}
// 校验重复的code值
public static void main(String[] args) {
StatusCode[] ApiStatusCodes = StatusCode.values();
List<Integer> codeList = new ArrayList<Integer>();
for (StatusCode ApiStatusCode : ApiStatusCodes) {
if (codeList.contains(ApiStatusCode.code)) {
System.out.println(ApiStatusCode.code);
} else {
// System.out.println(ApiStatusCode.code() + "--" +
// ApiStatusCode.message());
codeList.add(ApiStatusCode.code());
}
}
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhongxia.dao.AccountsMapper">
<resultMap id="AccountMap" type="com.zhongxia.pojo.AccountsEntity">
<id column="id" property="id"/>
<result column="uuid" property="uuid"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="phone" property="phone"/>
<result column="email" property="email"/>
<result column="salt" property="salt"/>
<result column="company_id" property="companyId"/>
<result column="create_time" property="createTime"/>
<result column="modify_time" property="modifyTime"/>
<result column="locked" property="locked"/>
<collection property="roles" ofType="com.zhongxia.pojo.RolesEntity" column="id">
<id column="rid" property="id"/>
<result column="rolename" property="rolename"/>
</collection>
</resultMap>
<select id="loadUserByUsername" resultMap="AccountMap">
SELECT r.id AS rid ,r.rolename ,u.* FROM user_roles r, user_account_role ur,user_accounts u WHERE ur.`role_id`=r.`id` AND u.id = ur.account_id AND username=#{username}
</select>
<select id="loadUserByPassword" resultMap="AccountMap">
SELECT r.id AS rid ,r.rolename ,u.* FROM user_roles r, user_account_role ur,user_accounts u WHERE ur.`role_id`=r.`id` AND u.id = ur.account_id AND password=#{password}
</select>
<update id="updatePassword" >
UPDATE `user_accounts` ua SET ua.`password` = #{newpassword} WHERE ua.`username` = #{username}
</update>
<update id="resetPassword" >
UPDATE `user_accounts` ua SET ua.`password` = #{resetPassword} WHERE ua.`username` = #{username}
</update>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhongxia.dao.PermissionsMapper">
<resultMap type="com.zhongxia.pojo.PermissionsEntity" id="PermissionMap">
<id column="id" property="id"/>
<result column="url" property="url"/>
<collection property="roles" ofType="com.zhongxia.pojo.RolesEntity" column="id">
<id column="rid" property="id"/><!-- 这里的column对应的是下面查询的别名,而不是表字段名 -->
<result column="rolename" property="rolename"/><!-- property对应JavaBean中的属性名 -->
</collection>
</resultMap>
<select id="getAllPermission" resultMap="PermissionMap">
select p.* , r.id As rid,r.rolename from user_permissions p
left join user_role_permission pr on p.`id`=pr.`permission_id`
left join user_roles r on pr.`role_id`=r.`id`
order by p.`id` desc
</select>
<select id="findPermissionsAll" resultType="com.zhongxia.pojo.PermissionsEntity">
SELECT * FROM user_permissions
</select>
<insert id="addPermissions" parameterType="com.zhongxia.pojo.PermissionsEntity">
INSERT INTO
user_permissions
(url,method,describes,locked,create_time,parent_id)
VALUES("","",#{permissions.describes},#{permissions.locked},NOW(),#{permissions.parentId});
</insert>
<update id="updatePermissionsById" parameterType="com.zhongxia.pojo.PermissionsEntity">
UPDATE user_permissions
<set>
describes = #{permissions.describes},
locked = #{permissions.locked},
modify_time = NOW(),
parent_id = #{permissions.parentId}
</set>
WHERE id = #{permissionsId};
</update>
<delete id="delPermissionsById">
DELETE FROM user_permissions WHERE id = #{permissionsId};
</delete>
</mapper>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhongxia.dao.RolesMapper">
<select id="roles" resultType="com.zhongxia.pojo.RolesEntity">
SELECT * FROM user_roles where locked=0;
</select>
<select id="getRolesByUrl" resultType="com.zhongxia.pojo.RolesEntity">
SELECT rolename FROM user_roles r, user_permissions p, user_role_permission pr
where pr.role_id = r.id and permission_id = p.id
and url=#{url} and p.locked=0;
</select>
<!--查询所有角色 -->
<select id="findRolesAll" resultType="com.zhongxia.pojo.RolesEntity">
SELECT id, role,
describes,locked,create_time,modify_time,roles_type FROM user_roles;
</select>
<!-- 查询角色 -->
<select id="findRoles" resultType="com.zhongxia.pojo.RolesEntity">
SELECT id, rolename,
describes,locked,create_time,modify_time,roles_type FROM user_roles;
</select>
<insert id="addRole" parameterType="com.zhongxia.pojo.RolesEntity">
INSERT INTO
user_roles
(rolename,describes,locked,create_time,roles_type)
VALUES(#{roles.rolename},#{roles.describes},#{roles.locked},NOW(),#{roles.rolesType});
</insert>
<insert id="addRelations" parameterType="java.util.List">
REPLACE INTO user_role_permission(
`role_id`, `permission_id`,company_id
)
VALUES
<foreach collection="rolePermRelation" index="index" item="item" separator="," >
(
#{roleId},#{item},1
)
</foreach>
</insert>
<update id="updateRoleByRoleId" parameterType="com.zhongxia.pojo.RolesEntity">
UPDATE user_roles
<set>
rolename = #{roles.rolename},
describes = #{roles.describes},
locked = #{roles.locked},
modify_time = NOW(),
roles_type = #{roles.rolesType}
<!-- <if test="productType.createTime == null">create_time = NOW()</if>
<if test="productType.createTime != null">modify_time = NOW()</if> -->
</set>
WHERE id = #{roleId} ;
</update>
<delete id="delRoleByRoleId">
DELETE FROM user_roles WHERE id = #{roleId};
<!-- DELETE FROM user_role_permission_init WHERE role_id = #{roleId}; -->
</delete>
<delete id="delRelations">
DELETE FROM user_role_permission WHERE role_id = #{roleId} and permission_id =#{deletePerID};
</delete>
</mapper>
这里是简单写了个页面
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>login</title>
</head>
<body>
<div id="login-box">
<h1>Spring Security 自定义登录页面</h1>
<div class="error" th:class="${error}? 'show error' : 'hide'" th:text="${error}"></div>
<div class="msg" th:class="${msg}? 'show msg' : 'hide'" th:text="${msg}"></div>
<form name='loginForm' action="/login" method='POST'>
<table>
<tr>
<td>用户名:</td>
<td><input type='text' name='username' /></td>
</tr>
<tr>
<td>密码:</td>
<td><input type='password' name='password' /></td>
</tr>
<tr>
<td>Remember me:</td>
<td><input type="checkbox" name="remember-me"/></td>
</tr>
<tr>
<td colspan='2'>
<input type="submit" value="提交" />
</td>
</tr>
</table>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
</form>
</div>
</body>
</html>
4.数据库
CREATE DATABASE /*!32312 IF NOT EXISTS*/`security_demo` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `security_demo`;
/*Table structure for table `user_account_role` */
DROP TABLE IF EXISTS `user_account_role`;
CREATE TABLE `user_account_role` (
`account_id` bigint(20) unsigned NOT NULL COMMENT '用户id',
`role_id` bigint(20) unsigned NOT NULL COMMENT '角色id',
PRIMARY KEY (`account_id`,`role_id`),
KEY `user_account_role_1` (`role_id`),
CONSTRAINT `user_account_role_1` FOREIGN KEY (`role_id`) REFERENCES `user_roles` (`id`),
CONSTRAINT `user_account_role_2` FOREIGN KEY (`account_id`) REFERENCES `user_accounts` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `user_account_role` */
insert into `user_account_role`(`account_id`,`role_id`) values (1,1),(2,2);
/*Table structure for table `user_accounts` */
DROP TABLE IF EXISTS `user_accounts`;
CREATE TABLE `user_accounts` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(256) NOT NULL COMMENT '由用户名+手机号+邮箱生成的登录账号',
`username` varchar(256) DEFAULT NULL COMMENT '用户名',
`phone` varchar(11) DEFAULT NULL COMMENT '电话',
`email` varchar(256) DEFAULT NULL COMMENT '邮件',
`password` varchar(256) NOT NULL COMMENT '密码',
`salt` varchar(256) DEFAULT NULL COMMENT '盐',
`locked` tinyint(1) DEFAULT '0' COMMENT '是否锁定(0表示未锁定,可用,1表示不可用)',
`company_code` bigint(20) unsigned DEFAULT NULL COMMENT '公司id',
`create_time` datetime DEFAULT NULL COMMENT '// 创建时间',
`modify_time` datetime DEFAULT NULL COMMENT '// 修改时间',
`account_type` int(10) unsigned NOT NULL COMMENT '账号类型',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
/*Data for the table `user_accounts` */
insert into `user_accounts`(`id`,`uuid`,`username`,`phone`,`email`,`password`,`salt`,`locked`,`company_code`,`create_time`,`modify_time`,`account_type`) values (1,'123','admin','15156565656','[email protected]','$2a$10$G19hmyZuyzeFcBbw/5V9U.ooxmudLPaCNws8ZVsb/cqWDE2XZWNEi',NULL,0,1,'2019-03-14 09:51:43','2019-03-14 09:51:47',0),(2,'123','user','12155556666','[email protected]','$2a$10$AYa/fMCvbPDZN3pFcwRAI.Tdq2esT3nQ1f53lGbCEqEU2wbJ9XDbu',NULL,0,1,'2019-03-14 09:52:48','2019-03-14 09:52:51',1);
/*Table structure for table `user_permissions` */
DROP TABLE IF EXISTS `user_permissions`;
CREATE TABLE `user_permissions` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`url` varchar(256) NOT NULL COMMENT '请求路径',
`method` varchar(256) NOT NULL COMMENT '请求风格',
`describes` varchar(256) NOT NULL COMMENT '功能描述',
`locked` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否锁定',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`modify_time` datetime DEFAULT NULL COMMENT '修改时间',
`parent_id` bigint(20) NOT NULL COMMENT '上级id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8;
/*Data for the table `user_permissions` */
insert into `user_permissions`(`id`,`url`,`method`,`describes`,`locked`,`create_time`,`modify_time`,`parent_id`) values (1,'/user/findAll','','查询所有',0,NULL,NULL,0),(2,'/user/findById','','根据id查询',0,NULL,NULL,0);
/*Table structure for table `user_role_permission` */
DROP TABLE IF EXISTS `user_role_permission`;
CREATE TABLE `user_role_permission` (
`role_id` bigint(20) unsigned NOT NULL,
`permission_id` bigint(20) unsigned NOT NULL,
`company_code` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`role_id`,`permission_id`,`company_code`),
KEY `user_role_permission_1` (`permission_id`),
CONSTRAINT `user_role_permission_1` FOREIGN KEY (`permission_id`) REFERENCES `user_permissions` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `user_role_permission_2` FOREIGN KEY (`role_id`) REFERENCES `user_roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
/*Data for the table `user_role_permission` */
insert into `user_role_permission`(`role_id`,`permission_id`,`company_code`) values (1,1,0),(1,2,0),(2,2,0);
/*Table structure for table `user_roles` */
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`rolename` varchar(256) NOT NULL COMMENT '角色名称',
`describes` varchar(256) NOT NULL COMMENT '角色描述',
`locked` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否锁定',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`modify_time` datetime DEFAULT NULL COMMENT '修改时间',
`roles_type` tinyint(1) unsigned NOT NULL DEFAULT '2' COMMENT ' // 0 admin 1默认 2自定义',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
/*Data for the table `user_roles` */
insert into `user_roles`(`id`,`rolename`,`describes`,`locked`,`create_time`,`modify_time`,`roles_type`) values (1,'ROLE_admin','管理员',0,'2019-03-14 16:31:10','2019-03-14 10:42:36',1),(2,'ROLE_zadmin','用户',0,'2019-03-14 09:54:11','2019-03-14 09:54:13',2);
5.启动测试
纯手写点个赞!