一、创建数据库表 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<String> urls = new ArrayList<>();
public List<String> getUrls() {
return urls;
}
public void setUrls(List<String> urls) {
this.urls = urls;
}
}
secure:
ignored:
urls: #安全路径白名单
- *.html
- *.js
- *.css
- *.png
- /favicon.ico
- /actuator
import com.lm.common.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Configuration
public class SecurityConfig {
@Autowired
private IgnoreUrlsConfig ignoreUrlsConfig;
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Autowired
private RestfulAccessDeniedHandler restfulAccessDeniedHandler;
@Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
private DynamicSecurityFilter dynamicSecurityFilter;
@Bean
SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry =
httpSecurity.authorizeRequests();
for (String url : ignoreUrlsConfig.getUrls()) {
registry.antMatchers(url).permitAll();
}
registry.antMatchers(HttpMethod.OPTIONS,"/**")
.permitAll();
httpSecurity.csrf()
.disable()
.cors().configurationSource(corsConfigurationSource()).and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest()
.authenticated();
httpSecurity.headers().cacheControl();
httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
httpSecurity.exceptionHandling()
.accessDeniedHandler(restfulAccessDeniedHandler)
.authenticationEntryPoint(restAuthenticationEntryPoint);
registry.and().addFilterBefore(dynamicSecurityFilter, FilterSecurityInterceptor.class);
return httpSecurity.build();
}
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("/**", configuration);
return source;
}
}
package com.lm.common.utils;
import cn.hutool.core.collection.CollUtil;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.Iterator;
@Component
public class DynamicAccessDecisionManager implements AccessDecisionManager {
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
if (CollUtil.isEmpty(configAttributes)){
return;
}
Iterator<ConfigAttribute> 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 fi = new FilterInvocation(servletRequest,servletResponse,filterChain);
if (request.getMethod().equals(HttpMethod.OPTIONS.toString())){
fi.getChain().doFilter(fi.getRequest(),fi.getResponse());
return;
}
PathMatcher pathMatcher = new AntPathMatcher();
List<String> urls = ignoreUrlsConfig.getUrls();
for (String url : urls) {
if (pathMatcher.match(url,request.getRequestURI())){
fi.getChain().doFilter(fi.getRequest(),fi.getResponse());
return;
}
}
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<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
List<ConfigAttribute> configAttributes = new ArrayList<>();
String url = ((FilterInvocation) object).getRequestUrl();
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<UmsPermission> 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()){
return SecurityConfig.createList("ROLE_LOGIN");
}
return configAttributes;
}
@Override
public Collection<ConfigAttribute> 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);
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)){
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
log.info("checking userName:{}",userName);
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<String, Object> 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<String,Object> 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<String> 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<UmsPermission> permissions;
public List<UmsPermission> getPermissions() {
return permissions;
}
public void setPermissions(List<UmsPermission> permissions) {
this.permissions = permissions;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
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<SimpleGrantedAuthority> 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<UmsRole> getUmsRole(Long id);
}
@Mapper
public interface UmsAdminRoleRelationMapper {
List<UmsPermission> getPermissionList(@Param("adminId") Long adminId);
}
service层
public interface AdminService {
public Map<String, Object> login(String userName,String passWord);
List<UmsPermission> 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<UmsPermission> permissionList = umsAdminRoleRelationMapper.getPermissionList(umsAdmin.getId());
umsAdmin.setPermissions(permissionList);
return umsAdmin;
}
throw new UsernameNotFoundException("用户名或密码错误");
}
@Override
public Map<String, Object> login(String userName, String passWord) {
Map<String, Object> 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<UmsPermission> getPermissionList(Long adminId) {
return umsAdminRoleRelationMapper.getPermissionList(adminId);
}
}
mapper映射
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.lm.mapper.UmsAdminRoleRelationMapper">
<select id="getPermissionList" resultType="com.lm.pojo.UmsPermission">
SELECT
p.*
FROM
ums_admin_role_relation ar
LEFT JOIN ums_role r ON ar.role_id = r.id
LEFT JOIN ums_role_permission_relation rp ON r.id = rp.role_id
LEFT JOIN ums_permission p ON rp.permission_id = p.id
WHERE
ar.admin_id = #{adminId}
AND p.id IS NOT NULL
AND p.id NOT IN (
SELECT
p.id
FROM
ums_admin_permission_relation pr
LEFT JOIN ums_permission p ON pr.permission_id = p.id
WHERE
pr.type = - 1
AND pr.admin_id = #{adminId}
)
UNION
SELECT
p.*
FROM
ums_admin_permission_relation pr
LEFT JOIN ums_permission p ON pr.permission_id = p.id
WHERE
pr.type = 1
AND pr.admin_id = #{adminId}
</select>
</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<String, Object> 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<UmsPermission> permissionList = umsAdminRoleRelationMapper.getPermissionList(id);
List<UmsPermission> 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<UmsPermission> permissions){
List<UmsPermission> list = new ArrayList<>();
for (UmsPermission permission : permissions) {
if (father.getId().equals(permission.getPid())){
father.setChildren(list);
father.getChildren().add(setChildren(permission,permissions));
}
}
return father;
}
}
|