Spring Security是Spring提供的一個安全框架,提供認證和受權功能,最主要的是它提供了簡單的使用方式,同時又有很高的靈活性,簡單,靈活,強大。前端
我我的博客系統採用的權限框架就是Spring Security,正好整合到SpringCloud裏面。
通常系統裏關於角色方面一般有這麼幾張表,角色表、用戶-角色表、菜單表、角色-菜單表等。java
不過我我的博客系統主要以wordpress做爲參考,沿用其12張表,如圖:web
<properties> <jjwt.version>0.9.0</jjwt.version> <spring-security-jwt.version>1.0.9.RELEASE</spring-security-jwt.version> </properties> <!-- springsecurity--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-jwt</artifactId> <version>${spring-security-jwt.version}</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>${jjwt.version}</version> </dependency>
package com.springcloud.blog.admin.config; import com.springcloud.blog.admin.security.UserAuthenticationProvider; import com.springcloud.blog.admin.security.UserPermissionEvaluator; import com.springcloud.blog.admin.security.handler.*; import com.springcloud.blog.admin.security.jwt.JWTAuthenticationTokenFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; /** * SpringSecurity配置類 * @Author youcong */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) //開啓權限註解,默認是關閉的 public class SecurityConfig extends WebSecurityConfigurerAdapter { /** * 自定義登陸成功處理器 */ @Autowired private UserLoginSuccessHandler userLoginSuccessHandler; /** * 自定義登陸失敗處理器 */ @Autowired private UserLoginFailureHandler userLoginFailureHandler; /** * 自定義註銷成功處理器 */ @Autowired private UserLogoutSuccessHandler userLogoutSuccessHandler; /** * 自定義暫無權限處理器 */ @Autowired private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler; /** * 自定義未登陸的處理器 */ @Autowired private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler; /** * 自定義登陸邏輯驗證器 */ @Autowired private UserAuthenticationProvider userAuthenticationProvider; /** * 加密方式 * @Author youcong */ @Bean public BCryptPasswordEncoder bCryptPasswordEncoder(){ return new BCryptPasswordEncoder(); } /** * 注入自定義PermissionEvaluator */ @Bean public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler(){ DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler(); handler.setPermissionEvaluator(new UserPermissionEvaluator()); return handler; } /** * 配置登陸驗證邏輯 */ @Override protected void configure(AuthenticationManagerBuilder auth){ //這裏可啓用咱們本身的登錄驗證邏輯 auth.authenticationProvider(userAuthenticationProvider); } /** * 配置security的控制邏輯 * @Author youcong * @Param http 請求 */ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() // 不進行權限驗證的請求或資源(從配置文件中讀取) .antMatchers(JWTConfig.antMatchers.split(",")).permitAll() // .antMatchers("/*").permitAll() // 其餘的須要登錄後才能訪問 .anyRequest().authenticated() .and() // 配置未登陸自定義處理類 .httpBasic().authenticationEntryPoint(userAuthenticationEntryPointHandler) .and() // 配置登陸地址 .formLogin() .loginProcessingUrl("/login/userLogin") // 配置登陸成功自定義處理類 .successHandler(userLoginSuccessHandler) // 配置登陸失敗自定義處理類 .failureHandler(userLoginFailureHandler) .and() // 配置登出地址 .logout() .logoutUrl("/login/userLogout") // 配置用戶登出自定義處理類 .logoutSuccessHandler(userLogoutSuccessHandler) .and() // 配置沒有權限自定義處理類 .exceptionHandling().accessDeniedHandler(userAuthAccessDeniedHandler) .and() // 開啓跨域 .cors() .and() // 取消跨站請求僞造防禦 .csrf().disable(); // 基於Token不須要session http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 禁用緩存 http.headers().cacheControl(); // 添加JWT過濾器 http.addFilter(new JWTAuthenticationTokenFilter(authenticationManager())); } }
package com.springcloud.blog.admin.config; import lombok.Getter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; /** * JWT配置類 * @Author youcong */ @Getter @Component @ConfigurationProperties(prefix = "jwt") public class JWTConfig { /** * 密鑰KEY */ public static String secret; /** * TokenKey */ public static String tokenHeader; /** * Token前綴字符 */ public static String tokenPrefix; /** * 過時時間 */ public static Integer expiration; /** * 不須要認證的接口 */ public static String antMatchers; public void setSecret(String secret) { this.secret = secret; } public void setTokenHeader(String tokenHeader) { this.tokenHeader = tokenHeader; } public void setTokenPrefix(String tokenPrefix) { this.tokenPrefix = tokenPrefix; } public void setExpiration(Integer expiration) { this.expiration = expiration * 1000; } public void setAntMatchers(String antMatchers) { this.antMatchers = antMatchers; } }
application.yml增長以下內容:正則表達式
# JWT配置 jwt: # 密匙KEY secret: JWTSecret # HeaderKEY tokenHeader: Authorization # Token前綴字符 tokenPrefix: challenger- # 過時時間 單位秒 1天后過時=86400 7天后過時=604800 expiration: 86400 # 配置不須要認證的接口 antMatchers: /index/**,/login/**,/favicon.ico # 有效時間 validTime: 7
package com.springcloud.blog.admin.security.handler; import com.springcloud.blog.admin.config.JWTConfig; import com.springcloud.blog.admin.security.entity.SelfUserEntity; import com.springcloud.blog.admin.utils.AccessAddressUtil; import com.springcloud.blog.admin.utils.JWTTokenUtil; import com.springcloud.blog.admin.utils.RedisUtil; import com.springcloud.blog.admin.utils.ResultUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; /** * @Description 登陸成功處理類 * @Author youcong */ @Component public class UserLoginSuccessHandler implements AuthenticationSuccessHandler { /** * 登陸成功返回結果 * @Author youcong */ @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication){ // 組裝JWT SelfUserEntity selfUserEntity = (SelfUserEntity) authentication.getPrincipal(); String token = JWTTokenUtil.createAccessToken(selfUserEntity); token = JWTConfig.tokenPrefix + token; // 封裝返回參數 Map<String,Object> resultData = new HashMap<>(); resultData.put("code","200"); resultData.put("msg", "登陸成功"); resultData.put("token",token); ResultUtil.responseJson(response,resultData); } }
package com.springcloud.blog.admin.security.handler; import com.springcloud.blog.admin.utils.ResultUtil; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.LockedException; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @Description 登陸失敗處理類 * @Author youcong */ @Component public class UserLoginFailureHandler implements AuthenticationFailureHandler { /** * 登陸失敗返回結果 * @Author youcong */ @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception){ // 這些對於操做的處理類能夠根據不一樣異常進行不一樣處理 if (exception instanceof UsernameNotFoundException){ System.out.println("【登陸失敗】"+exception.getMessage()); ResultUtil.responseJson(response,ResultUtil.resultCode(500,"用戶名不存在")); } if (exception instanceof LockedException){ System.out.println("【登陸失敗】"+exception.getMessage()); ResultUtil.responseJson(response,ResultUtil.resultCode(500,"用戶被凍結")); } if (exception instanceof BadCredentialsException){ System.out.println("【登陸失敗】"+exception.getMessage()); ResultUtil.responseJson(response,ResultUtil.resultCode(500,"密碼錯誤")); } ResultUtil.responseJson(response,ResultUtil.resultCode(500,"登陸失敗")); } }
package com.springcloud.blog.admin.security.handler; import com.springcloud.blog.admin.utils.DateUtil; import com.springcloud.blog.admin.utils.RedisUtil; import com.springcloud.blog.admin.utils.ResultUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.Map; /** * 登出成功處理類 * @Author youcong */ @Component public class UserLogoutSuccessHandler implements LogoutSuccessHandler { /** * 用戶登出返回結果 * 這裏應該讓前端清除掉Token * @Author youcong */ @Override public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication){ Map<String,Object> resultData = new HashMap<>(); resultData.put("code","200"); resultData.put("msg", "登出成功"); SecurityContextHolder.clearContext(); ResultUtil.responseJson(response,ResultUtil.resultSuccess(resultData)); } }
package com.springcloud.blog.admin.security.handler; import com.springcloud.blog.admin.utils.ResultUtil; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @Description 暫無權限處理類 * @Author youcong */ @Component public class UserAuthAccessDeniedHandler implements AccessDeniedHandler { /** * 暫無權限返回結果 * @Author youcong */ @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exception){ ResultUtil.responseJson(response,ResultUtil.resultCode(403,"未受權")); } }
package com.springcloud.blog.admin.security.handler; import com.springcloud.blog.admin.utils.ResultUtil; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 用戶未登陸處理類 * @Author youcong */ @Component public class UserAuthenticationEntryPointHandler implements AuthenticationEntryPoint { /** * 用戶未登陸返回結果 * @Author youcong */ @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception){ ResultUtil.responseJson(response,ResultUtil.resultCode(401,"未登陸")); } }
自定義登陸驗證這個類,須要根據實際狀況重寫。一般來講改動不大。spring
package com.springcloud.blog.admin.security; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.springcloud.blog.admin.entity.Usermeta; import com.springcloud.blog.admin.entity.Users; import com.springcloud.blog.admin.security.entity.SelfUserEntity; import com.springcloud.blog.admin.service.UsermetaService; import com.springcloud.blog.admin.service.UsersService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.LockedException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Component; import java.util.HashSet; import java.util.List; import java.util.Set; /** * 自定義登陸驗證 * * @Author youcong */ @Component public class UserAuthenticationProvider implements AuthenticationProvider { @Autowired private UsersService usersService; @Autowired private UsermetaService usermetaService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // 獲取表單輸入中返回的用戶名 String userName = (String) authentication.getPrincipal(); // 獲取表單中輸入的密碼 String password = (String) authentication.getCredentials(); // 查詢用戶是否存在 SelfUserEntity userInfo = usersService.getUserInfo(userName); if (userInfo.getUsername() == null || userInfo.getUsername() == "") { throw new UsernameNotFoundException("用戶名不存在"); } // 咱們還要判斷密碼是否正確,這裏咱們的密碼使用BCryptPasswordEncoder進行加密的 if (!new BCryptPasswordEncoder().matches(password, userInfo.getPassword())) { throw new BadCredentialsException("密碼不正確"); } // 還能夠加一些其餘信息的判斷,好比用戶帳號已停用等判斷 if (userInfo.getStatus().equals("1")) { throw new LockedException("該用戶已被凍結"); } // 角色集合 Set<GrantedAuthority> authorities = new HashSet<>(); EntityWrapper<Usermeta> roleWrapper = new EntityWrapper<>(); roleWrapper.eq("user_id",userInfo.getUserId()); roleWrapper.eq("meta_key","wp_user_level"); // 查詢用戶角色 List<Usermeta> sysRoleEntityList = usermetaService.selectList(roleWrapper); for (Usermeta sysRoleEntity: sysRoleEntityList){ authorities.add(new SimpleGrantedAuthority("ROLE_" + sysRoleEntity.getMetaValue())); } userInfo.setAuthorities(authorities); // 進行登陸 return new UsernamePasswordAuthenticationToken(userInfo, password, authorities); } @Override public boolean supports(Class<?> authentication) { return true; } }
package com.springcloud.blog.admin.security; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.springcloud.blog.admin.entity.Usermeta; import com.springcloud.blog.admin.service.UsermetaService; import org.apache.catalina.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.PermissionEvaluator; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; import java.io.Serializable; import java.util.HashSet; import java.util.List; import java.util.Set; /** * 自定義權限註解驗證 * @Author youcong */ @Component public class UserPermissionEvaluator implements PermissionEvaluator { @Autowired private UsermetaService usermetaService; /** * hasPermission鑑權方法 * 這裏僅僅判斷PreAuthorize註解中的權限表達式 * 實際中能夠根據業務需求設計數據庫經過targetUrl和permission作更復雜鑑權 * 固然targetUrl不必定是URL能夠是數據Id還能夠是管理員標識等,這裏根據需求自行設計 * @Author youcong * @Param authentication 用戶身份(在使用hasPermission表達式時Authentication參數默認會自動帶上) * @Param targetUrl 請求路徑 * @Param permission 請求路徑權限 * @Return boolean 是否經過 */ @Override public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) { // 獲取用戶信息 Usermeta selfUserEntity =(Usermeta) authentication.getPrincipal(); // 查詢用戶權限(這裏能夠將權限放入緩存中提高效率) Set<String> permissions = new HashSet<>(); EntityWrapper<Usermeta> roleWrapper = new EntityWrapper<>(); roleWrapper.eq("user_id",selfUserEntity.getUserId()); roleWrapper.eq("meta_key","wp_user_level"); List<Usermeta> sysMenuEntityList = usermetaService.selectList(roleWrapper); for (Usermeta sysMenuEntity:sysMenuEntityList) { permissions.add(sysMenuEntity.getMetaValue()); } // 權限對比 if (permissions.contains(permission.toString())){ return true; } return true; } @Override public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) { return false; } }
package com.springcloud.blog.admin.security.entity; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import java.io.Serializable; import java.util.Collection; import java.util.Map; /** * SpringSecurity用戶的實體 * 注意:這裏必需要實現UserDetails接口 * * @Author youcong */ public class SelfUserEntity implements Serializable, UserDetails { private static final long serialVersionUID = 1L; /** * 用戶ID */ private Long userId; /** * 用戶名 */ private String username; /** * 密碼 */ private String password; /** * 狀態 */ private String status; /** * 顯示名稱 */ private String displayName; /** * 用戶參數 */ private Map<String, String> userParamMap; /** * 用戶角色 */ private Collection<GrantedAuthority> authorities; /** * 帳戶是否過時 */ private boolean isAccountNonExpired = false; /** * 帳戶是否被鎖定 */ private boolean isAccountNonLocked = false; /** * 證書是否過時 */ private boolean isCredentialsNonExpired = false; /** * 帳戶是否有效 */ private boolean isEnabled = true; public static long getSerialVersionUID() { return serialVersionUID; } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } @Override public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void setAuthorities(Collection<GrantedAuthority> authorities) { this.authorities = authorities; } public void setEnabled(boolean enabled) { isEnabled = enabled; } public void setStatus(String status) { this.status = status; } public String getStatus() { return status; } public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } public Map<String, String> getUserParamMap() { return userParamMap; } public void setUserParamMap(Map<String, String> userParamMap) { this.userParamMap = userParamMap; } @Override public Collection<GrantedAuthority> getAuthorities() { return authorities; } @Override public boolean isAccountNonExpired() { return isAccountNonExpired; } @Override public boolean isAccountNonLocked() { return isAccountNonLocked; } @Override public boolean isCredentialsNonExpired() { return isCredentialsNonExpired; } @Override public boolean isEnabled() { return isEnabled; } }
package com.springcloud.blog.admin.security.jwt; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.springcloud.blog.admin.config.JWTConfig; import com.springcloud.blog.admin.security.entity.SelfUserEntity; import com.springcloud.blog.admin.utils.CollectionUtil; import com.springcloud.blog.admin.utils.JWTTokenUtil; import com.springcloud.blog.admin.utils.RedisUtil; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.util.StringUtils; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * JWT接口請求校驗攔截器 * 請求接口時會進入這裏驗證Token是否合法和過時 * * @Author youcong */ public class JWTAuthenticationTokenFilter extends BasicAuthenticationFilter { public JWTAuthenticationTokenFilter(AuthenticationManager authenticationManager) { super(authenticationManager); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 獲取請求頭中JWT的Token String tokenHeader = request.getHeader(JWTConfig.tokenHeader); if (null != tokenHeader && tokenHeader.startsWith(JWTConfig.tokenPrefix)) { try { // 截取JWT前綴 String token = tokenHeader.replace(JWTConfig.tokenPrefix, ""); // 解析JWT Claims claims = Jwts.parser() .setSigningKey(JWTConfig.secret) .parseClaimsJws(token) .getBody(); // 獲取用戶名 String username = claims.getSubject(); String userId = claims.getId(); if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(userId)) { // 獲取角色 List<GrantedAuthority> authorities = new ArrayList<>(); String authority = claims.get("authorities").toString(); if (!StringUtils.isEmpty(authority)) { List<Map<String, String>> authorityMap = JSONObject.parseObject(authority, List.class); for (Map<String, String> role : authorityMap) { if (!StringUtils.isEmpty(role)) { authorities.add(new SimpleGrantedAuthority(role.get("authority"))); } } } //組裝參數 SelfUserEntity selfUserEntity = new SelfUserEntity(); selfUserEntity.setUsername(claims.getSubject()); selfUserEntity.setUserId(Long.parseLong(claims.getId())); selfUserEntity.setAuthorities(authorities); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(selfUserEntity, userId, authorities); SecurityContextHolder.getContext().setAuthentication(authentication); } } catch (ExpiredJwtException e) { System.out.println("Token過時"); } catch (Exception e) { System.out.println("Token無效"); } } filterChain.doFilter(request, response); return; } }
package com.springcloud.blog.admin.security.service; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.springcloud.blog.admin.entity.Users; import com.springcloud.blog.admin.security.entity.SelfUserEntity; import com.springcloud.blog.admin.service.UsersService; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; /** * SpringSecurity用戶的業務實現 * * @Author youcong */ @Component public class SelfUserDetailsService implements UserDetailsService { @Autowired private UsersService usersService; /** * 查詢用戶信息 * * @Author youcong * @Param username 用戶名 * @Return UserDetails SpringSecurity用戶信息 */ @Override public SelfUserEntity loadUserByUsername(String username) throws UsernameNotFoundException { EntityWrapper<Users> wrapper = new EntityWrapper<>(); //郵箱正則表達式 String expr = "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})$"; //是否爲郵箱 if (username.matches(expr)) { wrapper.eq("user_email", username); } else { wrapper.eq("user_login", username); } // 查詢用戶信息 Users sysUserEntity = usersService.selectOne(wrapper); if (sysUserEntity != null) { // 組裝參數 SelfUserEntity selfUserEntity = new SelfUserEntity(); BeanUtils.copyProperties(sysUserEntity, selfUserEntity); return selfUserEntity; } return null; } }
當@EnableGlobalMethodSecurity(securedEnabled=true)的時候,@Secured可使用。數據庫
@PostMapping("/helloUser") @Secured({"ROLE_normal","ROLE_admin"}) public Map<String, Object> initDashboard() { Map<String, Object> result = new HashMap<>(); result.put(ResponseDict.RESPONSE_TITLE_KEY, "儀表盤初始化"); result.put(ResponseDict.RESPONSE_DATA_KEY, dashboardService.initDashboard()); return ResultUtil.resultSuccess(result); }
說明:擁有normal或者admin角色的用戶均可以方法helloUser()方法。另外須要注意的是這裏匹配的字符串須要添加前綴「ROLE_「。express
Spring的 @PreAuthorize/@PostAuthorize 註解更適合方法級的安全,也支持Spring 表達式語言,提供了基於表達式的訪問控制。apache
當@EnableGlobalMethodSecurity(prePostEnabled=true)的時候,@PreAuthorize可使用:json
@PostMapping("/initDashboard") @PreAuthorize("hasRole('100')") public Map<String, Object> initDashboard() { Map<String, Object> result = new HashMap<>(); result.put(ResponseDict.RESPONSE_TITLE_KEY, "儀表盤初始化"); result.put(ResponseDict.RESPONSE_DATA_KEY, dashboardService.initDashboard()); return ResultUtil.resultSuccess(result); }
@PostAuthorize 註解使用並很少,在方法執行後再進行權限驗證,適合驗證帶有返回值的權限,Spring EL 提供 返回對象可以在表達式語言中獲取返回的對象returnObject。跨域
當@EnableGlobalMethodSecurity(prePostEnabled=true)的時候,@PostAuthorize可使用:
@GetMapping("/getUserInfo") @PostAuthorize(" returnObject!=null && returnObject.username == authentication.name") public User getUserInfo() { Object pricipal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); User user; if("anonymousUser".equals(pricipal)) { user = null; }else { user = (User) pricipal; } return user; }
(1)登陸測試,拿到token,如圖:
(2)請求中若是不攜帶token的話,請求其它接口就會顯示沒有登陸的提示,如圖:
(3)正確的請求應當攜帶token,就像下面這樣,如圖:
(4)沒有權限請求,如圖: