一、创建数据库表
DROp TABLE IF EXISTS luo_admin;
CREATE TABLE luo_admin (
id bigint(20) NOT NULL AUTO_INCREMENT,
username varchar(64) DEFAULT NULL,
password varchar(64) DEFAULT NULL,
icon varchar(500) DEFAULT NULL COMMENT ‘头像’,
email varchar(100) DEFAULT NULL COMMENT ‘邮箱’,
nick_name varchar(200) DEFAULT NULL COMMENT ‘昵称’,
note varchar(500) DEFAULT NULL COMMENT ‘备注信息’,
create_time datetime DEFAULT NULL COMMENT ‘创建时间’,
login_time datetime DEFAULT NULL COMMENT ‘最后登录时间’,
status int(1) DEFAULT ‘1’ COMMENT ‘帐号启用状态:0->禁用;1->启用’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COMMENT=‘后台用户表’;
添加数据:
INSERT INTO luo_admin VALUES (3, ‘admin’, ‘$2a
10
10
10TyteFqX1w78EDX81d4wr6.pJEYm9b9BdjJ1QF/U./ZEz9RuubWOE2’, ‘http://macro-oss.oss-cn-shenzhen.aliyuncs.com/mall/images/20190129/170157_yIl3_1767531.jpg’, ‘admin@163.com’, ‘系统管理员’, ‘系统管理员’, ‘2018-10-08 13:32:47’, ‘2022-06-21 10:35:39’, 1);
INSERT INTO luo_admin VALUES (10, ‘Test’, ‘$2a
10
10
10amtbA4JqnEshTdTKBAYPzumwDu4PMlbnulYPjGncfra2wXs92ao2K’, NULL, ‘testqq.com’, ‘测试账号’, ‘111’, ‘2022-06-21 10:30:21’, ‘2022-06-21 10:32:50’, 1);
DROP TABLE IF EXISTS luo_admin_permission_relation;
CREATE TABLE luo_admin_permission_relation (
id bigint(20) NOT NULL AUTO_INCREMENT,
admin_id bigint(20) DEFAULT NULL,
permission_id bigint(20) DEFAULT NULL,
type int(1) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COMMENT=‘后台用户和权限关系表(除角色中定义的权限以外的加减权限)’;
INSERT INTO luo_admin_permission_relation VALUES (1, 3, 16, -1);
INSERT INTO luo_admin_permission_relation VALUES (2, 3, 17, -1);
INSERT INTO luo_admin_permission_relation VALUES (3, 3, 18, -1);
INSERT INTO luo_admin_permission_relation VALUES (4, 3, 19, -1);
INSERT INTO luo_admin_permission_relation VALUES (5, 3, 20, -1);
INSERT INTO luo_admin_permission_relation VALUES (6, 3, 21, -1);
CREATE TABLE luo_admin_role_relation (
id bigint(20) NOT NULL AUTO_INCREMENT,
admin_id bigint(20) DEFAULT NULL,
role_id bigint(20) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8 COMMENT=‘后台用户和角色关系表’;
INSERT INTO luo_admin_role_relation VALUES (13, 3, 1);
INSERT INTO luo_admin_role_relation VALUES (21, 3, 5);
INSERT INTO luo_admin_role_relation VALUES (22, 10, 5);
CREATE TABLE luo_permission (
id bigint(20) NOT NULL AUTO_INCREMENT,
pid bigint(20) DEFAULT NULL COMMENT ‘父级权限id’,
name varchar(100) DEFAULT NULL COMMENT ‘名称’,
value varchar(200) DEFAULT NULL COMMENT ‘权限值’,
component varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ‘组件名’,
type int(1) DEFAULT NULL COMMENT ‘权限类型:0->目录;1->菜单;2->按钮(接口绑定权限)’,
uri varchar(200) DEFAULT NULL COMMENT ‘前端资源路径’,
title varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT ‘标题’,
create_time datetime DEFAULT NULL COMMENT ‘创建时间’,
status int(1) DEFAULT NULL COMMENT ‘启用状态;0->禁用;1->启用’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8 COMMENT=‘后台用户权限表’;
INSERT INTO luo_permission VALUES (1, 0, ‘Layout’, ‘pms:medicine:redad’, ‘Layout’, NULL, ‘/’, ‘Layout’, ‘2022-06-15 21:11:28’, 1);
INSERT INTO luo_permission VALUES (2, 1, ‘Home’, ‘pms:medicine:redad’, ‘Home’, NULL, ‘/home’, ‘首页’, ‘2022-06-15 21:11:31’, 1);
INSERT INTO luo_permission VALUES (3, 1, ‘BaseCompany’, ‘pms:medicine:redad’, ‘CompanyManage’, NULL, ‘/base/company’, ‘医药公司管理’, ‘2022-06-15 21:16:08’, 1);
INSERT INTO luo_permission VALUES (4, 1, ‘BaseSale’, ‘pms:medicine:redad’, ‘SaleManage’, NULL, ‘/base/sale’, ‘销售地点管理’, ‘2022-06-15 21:16:11’, 1);
INSERT INTO luo_permission VALUES (5, 1, ‘BaseCity’, ‘pms:medicine:redad’, ‘CityManage’, NULL, ‘/base/city’, ‘城市信息管理’, ‘2022-06-15 21:16:15’, 1);
INSERT INTO luo_permission VALUES (6, 1, ‘ManageDrug’, ‘pms:medicine:redad’, ‘DrugManage’, NULL, ‘/manage/drug’, ‘药品信息管理’, ‘2022-06-15 21:16:18’, 1);
INSERT INTO luo_permission VALUES (7, 1, ‘MedicalPolicy’, ‘pms:medicine:redad’, ‘MedicalPolicy’, NULL, ‘/manage/medical/policy’, ‘医保政策管理’, ‘2022-06-15 21:16:21’, 1);
INSERT INTO luo_permission VALUES (8, 1, ‘CompanyPolicy’, ‘pms:medicine:redad’, ‘CompanyPolicy’, NULL, ‘/manage/company/policy’, ‘医药公司政策管理’, ‘2022-06-15 21:16:24’, 1);
INSERT INTO luo_permission VALUES (9, 1, ‘DoctorManage’, ‘pms:medicine:redad’, ‘DoctorManage’, NULL, ‘/manage/doctor’, ‘医生信息管理’, ‘2022-06-15 21:16:28’, 1);
INSERT INTO luo_permission VALUES (10, 1, ‘MaterialManage’, ‘pms:medicine:redad’, ‘MaterialManage’, NULL, ‘/manage/material’, ‘必备材料管理’, ‘2022-06-15 21:16:32’, 1);
INSERT INTO luo_permission VALUES (12, 1, ‘luo’, ‘pms:medicine:redad’, ‘Layout’, NULL, ‘/admin’, ‘权限’, ‘2022-06-16 11:40:08’, 1);
INSERT INTO luo_permission VALUES (13, 12, ‘admin’, ‘pms:medicine:redad’, ‘admin’, NULL, ‘/luo/admin’, ‘用户列表’, ‘2022-06-16 17:16:44’, 1);
INSERT INTO luo_permission VALUES (14, 12, ‘role’, ‘pms:medicine:redad’, ‘role’, NULL, ‘/luo/role’, ‘角色列表’, ‘2022-06-16 17:18:44’, 1);
INSERT INTO luo_permission VALUES (15, 12, ‘allocMenu’, ‘pms:medicine:redad’, ‘allocMenu’, NULL, ‘/luo/allocMenu’, ‘菜单列表’, ‘2022-06-16 17:20:47’, 1);
INSERT INTO luo_permission VALUES (16, 0, ‘adminList’, ‘pms:medicine:redad’, ‘adminList’, NULL, ‘/api/admin/list’, ‘获取用户列表’, ‘2022-06-19 23:06:25’, 1);
INSERT INTO luo_permission VALUES (17, 0, ‘adminRole’, ‘pms:medicine:redad’, ‘adminRole’, NULL, ‘/api/role/listAll’, ‘获取角色列表’, ‘2022-06-19 23:23:11’, 1);
INSERT INTO luo_permission VALUES (18, 0, ‘adminRoleUpdate’, ‘pms:medicine:add’, ‘adminRoleUpdate’, NULL, ‘/api/admin/role/update’, ‘修改用户角色’, ‘2022-06-20 11:02:53’, 1);
INSERT INTO luo_permission VALUES (19, 0, ‘updateAdmin’, ‘pms:medicine:update’, ‘updateAdmin’, NULL, ‘/api/admin/update/v/’, ‘修改用户数据’, ‘2022-06-20 11:21:51’, 1);
INSERT INTO luo_permission VALUES (20, 0, ‘deleteAdmin’, ‘pms:medicine:delete’, ‘deleteAdmin’, NULL, ‘/api/admin/delete/v/’, ‘删除用户数据’, ‘2022-06-21 09:47:31’, 1);
INSERT INTO luo_permission VALUES (21, 0, ‘addAdmin’, ‘pms:medicine:add’, ‘addAdmin’, NULL, ‘/api/admin/register’, ‘添加用户数据’, ‘2022-06-21 10:13:45’, 1);
DROP TABLE IF EXISTS luo_role;
CREATE TABLE luo_role (
id bigint(20) NOT NULL AUTO_INCREMENT,
name varchar(100) DEFAULT NULL COMMENT ‘名称’,
description varchar(500) DEFAULT NULL COMMENT ‘描述’,
admin_count int(11) DEFAULT NULL COMMENT ‘后台用户数量’,
create_time datetime DEFAULT NULL COMMENT ‘创建时间’,
status int(1) DEFAULT ‘1’ COMMENT ‘启用状态:0->禁用;1->启用’,
sort int(11) DEFAULT ‘0’,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT=‘后台用户角色表’;
INSERT INTO luo_role VALUES (1, ‘系统管理员’, ‘系统管理员’, 0, ‘2018-09-30 15:46:11’, 1, 0);
INSERT INTO luo_role VALUES (5, ‘医生’, ‘医生’, 0, ‘2022-06-20 10:50:48’, 1, 0);
DROP TABLE IF EXISTS luo_role_permission_relation;
CREATE TABLE luo_role_permission_relation (
id bigint(20) NOT NULL AUTO_INCREMENT,
role_id bigint(20) DEFAULT NULL,
permission_id bigint(20) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8 COMMENT=‘后台用户角色和权限关系表’;
INSERT INTO luo_role_permission_relation VALUES (1, 1, 1);
INSERT INTO luo_role_permission_relation VALUES (2, 1, 2);
INSERT INTO luo_role_permission_relation VALUES (3, 1, 3);
INSERT INTO luo_role_permission_relation VALUES (4, 1, 4);
INSERT INTO luo_role_permission_relation VALUES (5, 1, 5);
INSERT INTO luo_role_permission_relation VALUES (6, 1, 6);
INSERT INTO luo_role_permission_relation VALUES (7, 1, 7);
INSERT INTO luo_role_permission_relation VALUES (8, 1, 8);
INSERT INTO luo_role_permission_relation VALUES (18, 1, 9);
INSERT INTO luo_role_permission_relation VALUES (19, 1, 10);
INSERT INTO luo_role_permission_relation VALUES (21, 1, 11);
INSERT INTO luo_role_permission_relation VALUES (22, 1, 12);
INSERT INTO luo_role_permission_relation VALUES (23, 1, 13);
INSERT INTO luo_role_permission_relation VALUES (24, 1, 14);
INSERT INTO luo_role_permission_relation VALUES (25, 1, 15);
INSERT INTO luo_role_permission_relation VALUES (28, 5, 1);
INSERT INTO luo_role_permission_relation VALUES (29, 5, 2);
二、创建SpringSecurity配置类
1.白名单配置
@Component
@ConfigurationProperties(prefix = "secure.ignored")
public class IgnoreUrlsConfig {
private List urls = new ArrayList<>();
public List getUrls() {
return urls;
}
public void setUrls(List urls) {
this.urls = urls;
}
}
secure:
ignored:
urls: #安全路径白名单
- *.html
- *.js
- *.css
- *.png
- /favicon.ico
- /actuator
public CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true);
configuration.addAllowedHeader("*");
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedOriginPatterns(Collections.singletonList("*"));
configuration.setMaxAge(Duration.ofHours(1));
source.registerCorsConfiguration("
@Component
public class DynamicAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
// 当接口未被配置资源时直接放行
if (CollUtil.isEmpty(configAttributes)){
return;
}
//将访问所需资源和用户拥有资源进行比较
Iterator iterator = configAttributes.iterator();
while (iterator.hasNext()){
ConfigAttribute configAttribute = iterator.next();
String needAuthority = configAttribute.getAttribute();
for (GrantedAuthority authority : authentication.getAuthorities()) {
if (needAuthority.trim().equals(authority.getAuthority())){
return;
}
}
}
throw new AccessDeniedException("抱歉,您没有访问权限");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class> clazz) {
return true;
}
}
package com.lm.common.utils;
import com.lm.config.IgnoreUrlsConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;
@Component
public class DynamicSecurityFilter extends AbstractSecurityInterceptor implements Filter {
@Autowired
private DynamicSecurityMetadataSource dynamicSecurityMetadataSource;
@Autowired
private IgnoreUrlsConfig ignoreUrlsConfig;
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
//FilterInvocation
FilterInvocation fi = new FilterInvocation(servletRequest,servletResponse,filterChain);
//如果是options请求就放行,
//当发起跨域请求时,由于安全原因,触发一定条件时浏览器会在正式请求之前自动先发起 OPTIONS 请求,即 CORS 预检请求,服务器若接受该跨域请求,浏览器才继续发起正式请求。
if (request.getMethod().equals(HttpMethod.OPTIONS.toString())){
fi.getChain().doFilter(fi.getRequest(),fi.getResponse());
return;
}
//白名单直接放行
PathMatcher pathMatcher = new AntPathMatcher();
List urls = ignoreUrlsConfig.getUrls();
for (String url : urls) {
if (pathMatcher.match(url,request.getRequestURI())){
fi.getChain().doFilter(fi.getRequest(),fi.getResponse());
return;
}
}
//此处会调用AccessDecisionManager中的decide方法进行鉴权操作
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(),fi.getResponse());
}catch (Exception e){
super.afterInvocation(token,null);
}
}
@Override
public Class> getSecureObjectClass() {
return FilterInvocation.class;
}
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return dynamicSecurityMetadataSource;
}
@Autowired
public void setMyAccessDecisionManager(DynamicAccessDecisionManager dynamicAccessDecisionManager){
super.setAccessDecisionManager(dynamicAccessDecisionManager);
}
}
package com.lm.common.utils;
import cn.hutool.core.util.URLUtil;
import com.lm.pojo.UmsAdmin;
import com.lm.pojo.UmsPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import java.util.*;
@Component
public class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Override
public Collection getAttributes(Object object) throws IllegalArgumentException {
List configAttributes = new ArrayList<>();
//获取当前访问路径
String url = ((FilterInvocation) object).getRequestUrl();
//http://localhost:8080/search/name=zhangsan&age=20 完事后只保留/search
//该方法用于获取URL链接中的path部分字符串
String path = URLUtil.getPath(url);
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Object principal1 = authentication.getPrincipal();
UmsAdmin userDetails = null;
if (principal1 instanceof UserDetails) {
userDetails = (UmsAdmin) principal1;
List permissions = userDetails.getPermissions();
PathMatcher pathMatcher = new AntPathMatcher();
for (UmsPermission umsPermission : permissions) {
if (pathMatcher.match(umsPermission.getUri(), path)) {
SecurityConfig securityConfig = new SecurityConfig(umsPermission.getId() + ":" + umsPermission.getValue());
configAttributes.add(securityConfig);
}
}
}
if (configAttributes.isEmpty()){
//没有匹配到资源,返回ROLE_LOGIN
return SecurityConfig.createList("ROLE_LOGIN");
}
//未设置权限返回空集合
return configAttributes;
}
@Override
public Collection getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class> clazz) {
return true;
}
}
package com.lm.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtTokenUtils jwtTokenUtil;
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String authHeader = request.getHeader(this.tokenHeader);
//如果获取的token不为空,并且 头部是相同的就返回true
if (authHeader != null && authHeader.startsWith(this.tokenHead)) {
String userToken = authHeader.substring(this.tokenHead.length());
String userName = jwtTokenUtil.getUserNameFromToken(userToken);
log.info("checking userName:{}",userName);
//判断数据库中是否有此用户,并且判断没有其他用户已登录
if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null){
UserDetails userDetails = this.userDetailsService.loadUserByUsername(userName);
//判断当前用户是否过期
if (jwtTokenUtil.validateToken(userToken,userDetails)){
//验证密码
//用户名和密码被过滤器获取到,封装成Authentication,通常情况下是UsernamePasswordAuthenticationToken这个实现类
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
log.info("checking userName:{}",userName);
//如果用户存在且用户的密码相同,则在SecurityContextHolder.getContext().setAuthentication()放入authentication
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
}
filterChain.doFilter(request,response);
}
}
package com.lm.common.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Component
@Slf4j
public class JwtTokenUtils {
@Value("${jwt.expiration}")
private Long expiration;
@Value("${jwt.secret}")
private String secret;
private static final String CLAIM_KEY_USERNAME = "sub";
private static final String CLAIM_KEY_CREATED = "created";
private String generateToken(Map claims) {
return Jwts.builder()
.setClaims(claims)
.setExpiration(generateExpirationDate())
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
private Claims getClaimsFromToken(String token){
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}catch (Exception e){
log.info("JWT格式验证失败:{}",token);
}
return claims;
}
public String getUserNameFromToken(String token){
String userName;
try {
Claims claims = getClaimsFromToken(token);
userName = claims.getSubject();
}catch (Exception e){
userName = null;
}
return userName;
}
public Date generateExpirationDate(){
return new Date(System.currentTimeMillis()+expiration*1000);
}
public boolean isTokenExpired(String token){
Date expiredDateFromToken = getExpiredDateFromToken(token);
return expiredDateFromToken.before(new Date());
}
public Date getExpiredDateFromToken(String token){
Claims claims = getClaimsFromToken(token);
return claims.getExpiration();
}
public boolean validateToken(String token, UserDetails userDetails){
String userName = getUserNameFromToken(token);
return userName.equals(userDetails.getUsername()) && !isTokenExpired(token);
}
public String generateToken(UserDetails userDetails){
Map claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME,userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED,new Date());
return generateToken(claims);
}
public boolean canRefresh(String token){return isTokenExpired(token);}
public String refreshToken(String token){
Claims claimsFromToken = getClaimsFromToken(token);
claimsFromToken.put(CLAIM_KEY_CREATED,new Date());
return generateToken(claimsFromToken);
}
}
package com.lm.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lm.common.api.CommonResult;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
CommonResult unauthorized = CommonResult.unauthorized(authException.getMessage());
response.getWriter().println(JSONObject.toJSONString(unauthorized));
response.getWriter().flush();
}
}
package com.lm.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.lm.common.api.CommonResult;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class RestfulAccessDeniedHandler implements AccessDeniedHandler{
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException e) throws IOException, ServletException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().println(JSONObject.toJSONString(CommonResult.forbidden(e.getMessage())));
response.getWriter().flush();
}
}
设置跨域
package com.lm.common.filter;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETe, PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader("Access-Control-Expose-Headers", "Location");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
Filter.super.destroy();
}
}
权限实体:
public class UmsAdmin implements Serializable, UserDetails {
private Long id;
private String username;
private String password;
@ApiModelProperty(value = "头像")
private String icon;
@ApiModelProperty(value = "邮箱")
private String email;
@ApiModelProperty(value = "昵称")
private String nickName;
@ApiModelProperty(value = "备注信息")
private String note;
@ApiModelProperty(value = "创建时间")
private Date createTime;
@ApiModelProperty(value = "最后登录时间")
private Date loginTime;
@ApiModelProperty(value = "帐号启用状态:0->禁用;1->启用")
private Integer status;
private static final long serialVersionUID = 1L;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String getUsername() {
return username;
}
private List permissions;
public List getPermissions() {
return permissions;
}
public void setPermissions(List permissions) {
this.permissions = permissions;
}
提示账号是否过期 true 末过期 false 过期
@Override
public boolean isAccountNonExpired() {
return true;
}
是否处于锁定状态
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
//指示用户凭证(密码) 是否过期 true 未过期 false过期
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
boolean enabled = true;
if (this.status == 0){
enabled = false;
}
return enabled;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public Collection extends GrantedAuthority> getAuthorities() {
List authorities = new ArrayList<>();
//返回当前用户的权限
for (UmsPermission umsPermission : permissions) {
authorities.add(new SimpleGrantedAuthority(umsPermission.getId() + ":" + umsPermission.getValue()));
}
return authorities;
}
@Override
public String getPassword() {
return password;
}
mapper 层
@Mapper
public interface AdminMapper {
public UmsAdmin loadAdminByUserName(String userName);
public List getUmsRole(Long id);
}
@Mapper
public interface UmsAdminRoleRelationMapper {
List getPermissionList(@Param("adminId") Long adminId);
}
service层
public interface AdminService {
public Map login(String userName,String passWord);
List getPermissionList(Long adminId);
@Service
@Slf4j
public class AdminServiceImpl implements AdminService, UserDetailsService {
@Autowired
private AdminMapper adminMapper;
@Autowired
private JwtTokenUtils jwtTokenUtil;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UmsAdminRoleRelationMapper umsAdminRoleRelationMapper;
@Autowired
private UmsRoleMapper umsRoleMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UmsAdmin umsAdmin = adminMapper.loadAdminByUserName(username);
if (umsAdmin != null){
List permissionList = umsAdminRoleRelationMapper.getPermissionList(umsAdmin.getId());
umsAdmin.setPermissions(permissionList);
return umsAdmin;
}
throw new UsernameNotFoundException("用户名或密码错误");
}
@Override
public Map login(String userName, String passWord) {
Map loginResult = new HashMap<>();
String token = null;
UserDetails userDetails = null;
try {
userDetails = loadUserByUsername(userName);
if(userDetails==null){
return loginResult;
}
if (!passwordEncoder.matches(passWord, userDetails.getPassword())) {
throw new BadCredentialsException("密码不正确");
}
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authentication);
token = jwtTokenUtil.generateToken(userDetails);
} catch (AuthenticationException e) {
log.warn("登录异常:{}", e.getMessage());
}
loginResult.put("token",token);
loginResult.put("userInfo",(UmsAdmin)userDetails);
return loginResult;
}
@Override
public List getPermissionList(Long adminId) {
return umsAdminRoleRelationMapper.getPermissionList(adminId);
}
}
mapper映射
控制层:
package com.lm.controller;
import com.lm.common.api.CommonResult;
import com.lm.mapper.UmsAdminRoleRelationMapper;
import com.lm.pojo.UmsPermission;
import com.lm.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class LoginController {
@Autowired
private AdminService adminService;
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Autowired
private UmsAdminRoleRelationMapper umsAdminRoleRelationMapper;
@RequestMapping(value = "/login",method = RequestMethod.POST)
public CommonResult login(@RequestParam String username, @RequestParam String password) {
Map loginResult = adminService.login(username, password);
if (loginResult.get("token") == null) {
return CommonResult.validateFailed("用户名或密码错误");
}
loginResult.put("tokenHead", tokenHead);
return CommonResult.success(loginResult);
}
@RequestMapping(value = "/permissions",method = RequestMethod.GET)
public CommonResult permissions(@RequestParam Long id){
List permissionList = umsAdminRoleRelationMapper.getPermissionList(id);
List failPermission = new ArrayList<>();
for (UmsPermission umsPermission : permissionList) {
if (umsPermission.getPid() == 0){
failPermission.add(setChildren(umsPermission, permissionList));
}
}
return CommonResult.success(failPermission);
}
public UmsPermission setChildren(UmsPermission father,List permissions){
List list = new ArrayList<>();
for (UmsPermission permission : permissions) {
if (father.getId().equals(permission.getPid())){
father.setChildren(list);
father.getChildren().add(setChildren(permission,permissions));
}
}
return father;
}
}



