Springboot詳解整合SpringSecurity實現(xiàn)全過程
使用Basic認證模式
1、maven依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <dependencies> <!-- SpringBoot整合Web組件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- springboot整合freemarker --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <!-->spring-boot 整合security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> </dependencies>
2、SecurityConfig 配置類
@Component @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { /** * 添加授權(quán)賬戶 * * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 設(shè)置用戶賬號信息和權(quán)限 auth.inMemoryAuthentication().withUser("kaico_admin").password("kaico") .authorities("/"); // 如果kaico_admin賬戶權(quán)限的情況 所有的接口都可以訪問,如果kaico_add 只能訪問addMember auth.inMemoryAuthentication().withUser("kaico_add").password("kaico") .authorities("/"); } @Override protected void configure(HttpSecurity http) throws Exception { //配置httpBasic Http協(xié)議認證 http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().httpBasic(); } /** * There is no PasswordEncoder mapped for the id "null" * 原因:升級為Security5.0以上密碼支持多中加密方式,恢復(fù)以前模式 * * @return */ @Bean public static NoOpPasswordEncoder passwordEncoder() { return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); } }
3、測試controller接口
@Controller public class IndexController { /** * 跳轉(zhuǎn)到首頁 * * @return */ @RequestMapping("/") public String index() { return "index"; } @ResponseBody @RequestMapping("/addMember") public String addMember() { return "新增用戶"; } @ResponseBody @RequestMapping("/delMember") public String delMember() { return "刪除用戶"; } @ResponseBody @RequestMapping("/updateMember") public String updateMember() { return "修改用戶"; } @ResponseBody @RequestMapping("/showMember") public String showMember() { return "查詢用戶"; } }
使用form表形式登錄
在上面Basic認證模式的基礎(chǔ)上修改SecurityConfig
配置類,修改下面的方法
@Override protected void configure(HttpSecurity http) throws Exception { //配置httpBasic Http協(xié)議認證 http.authorizeRequests().antMatchers("/**").fullyAuthenticated().and().formLogin(); }
springSecurity默認提供登錄頁面,如下圖所示:
注意:使用表單登錄之后,登錄成功之后默認跳轉(zhuǎn)首頁,也就是請求路徑/
,沒有該請求路徑的話會報錯。
實現(xiàn)權(quán)限控制
上面的案例只是實現(xiàn)了登錄認證,但是還沒有實現(xiàn)權(quán)限控制。
在上面的基礎(chǔ)上修改
1、修改SecurityConfig
配置類
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 設(shè)置用戶賬號信息和權(quán)限 auth.inMemoryAuthentication().withUser("kaico_admin").password("kaico") .authorities("addMember", "delMember", "updateMember", "showMember" ); // 如果kaico_admin賬戶權(quán)限的情況 所有的接口都可以訪問,如果kaico_add 只能訪問addMember auth.inMemoryAuthentication().withUser("kaico_add").password("kaico") .authorities("addMember"); } @Override protected void configure(HttpSecurity http) throws Exception { //配置權(quán)限 http.authorizeRequests().antMatchers("/addMember").hasAnyAuthority("addMember") .antMatchers("/addMember").hasAnyAuthority("addMember") .antMatchers("/delMember").hasAnyAuthority("delMember") .antMatchers("/updateMember").hasAnyAuthority("updateMember") .antMatchers("/showMember").hasAnyAuthority("showMember") .antMatchers("/**").fullyAuthenticated().and().formLogin(); }
沒有權(quán)限報403錯誤
修改403權(quán)限不足頁面
1、增加配置類
@Configuration public class WebServerAutoConfiguration { @Bean public ConfigurableServletWebServerFactory webServerFactory() { TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400"); ErrorPage errorPage401 = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401"); ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN, "/error/403"); ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"); ErrorPage errorPage415 = new ErrorPage(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "/error/415"); ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"); factory.addErrorPages(errorPage400, errorPage401, errorPage403, errorPage404, errorPage415, errorPage500); return factory; } }
2、增加對應(yīng)的錯誤請求路徑
@RestController public class ErrorController { @RequestMapping("/error/403") public String error403(){ return "您當(dāng)前訪問的接口權(quán)限不足"; } }
自定義登錄頁面
1、登錄頁面準備
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <h1>權(quán)限控制登陸系統(tǒng)</h1> <form action="/login" method="post"> <span>用戶名稱</span><input type="text" name="username"/> <br> <span>用戶密碼</span><input type="password" name="password"/> <br> <input type="submit" value="登陸"> </form> <#if RequestParameters['error']??> 用戶名稱或者密碼錯誤 </#if> </body> </html>
2、修改SecurityConfig
配置類
@Override protected void configure(HttpSecurity http) throws Exception { //配置權(quán)限 http.authorizeRequests().antMatchers("/addMember").hasAnyAuthority("addMember") .antMatchers("/addMember").hasAnyAuthority("addMember") .antMatchers("/delMember").hasAnyAuthority("delMember") .antMatchers("/updateMember").hasAnyAuthority("updateMember") .antMatchers("/showMember").hasAnyAuthority("showMember") .antMatchers("/login").permitAll() //放行登錄請求頁面 .antMatchers("/**").fullyAuthenticated() .and().formLogin().loginPage("/login").and().csrf().disable(); }
3、增加登錄頁面請求controller
@Controller public class LoginController { @RequestMapping("/login") public String login(){ return "login"; } }
結(jié)合數(shù)據(jù)庫實現(xiàn)RBAC權(quán)限模型權(quán)限控制
環(huán)境準備
數(shù)據(jù)庫
RBAC模型相關(guān)數(shù)據(jù)庫表關(guān)系圖
SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for sys_permission -- ---------------------------- DROP TABLE IF EXISTS `sys_permission`; CREATE TABLE `sys_permission` ( `id` int(10) NOT NULL, `permName` varchar(50) DEFAULT NULL, `permTag` varchar(50) DEFAULT NULL, `url` varchar(255) DEFAULT NULL COMMENT '請求url', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_permission -- ---------------------------- INSERT INTO `sys_permission` VALUES ('1', '查詢用戶', 'showMember', '/showMember'); INSERT INTO `sys_permission` VALUES ('2', '添加用戶', 'addMember', '/addMember'); INSERT INTO `sys_permission` VALUES ('3', '修改用戶', 'updateMember', '/updateMember'); INSERT INTO `sys_permission` VALUES ('4', '刪除用戶', 'delMember', '/delMember'); -- ---------------------------- -- Table structure for sys_role -- ---------------------------- DROP TABLE IF EXISTS `sys_role`; CREATE TABLE `sys_role` ( `id` int(10) NOT NULL, `roleName` varchar(50) DEFAULT NULL, `roleDesc` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_role -- ---------------------------- INSERT INTO `sys_role` VALUES ('1', 'admin', '管理員'); INSERT INTO `sys_role` VALUES ('2', 'add_user', '添加管理員'); -- ---------------------------- -- Table structure for sys_role_permission -- ---------------------------- DROP TABLE IF EXISTS `sys_role_permission`; CREATE TABLE `sys_role_permission` ( `role_id` int(10) DEFAULT NULL, `perm_id` int(10) DEFAULT NULL, KEY `FK_Reference_3` (`role_id`), KEY `FK_Reference_4` (`perm_id`), CONSTRAINT `FK_Reference_4` FOREIGN KEY (`perm_id`) REFERENCES `sys_permission` (`id`), CONSTRAINT `FK_Reference_3` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_role_permission -- ---------------------------- INSERT INTO `sys_role_permission` VALUES ('1', '1'); INSERT INTO `sys_role_permission` VALUES ('1', '2'); INSERT INTO `sys_role_permission` VALUES ('1', '3'); INSERT INTO `sys_role_permission` VALUES ('1', '4'); INSERT INTO `sys_role_permission` VALUES ('2', '2'); -- ---------------------------- -- Table structure for sys_user -- ---------------------------- DROP TABLE IF EXISTS `sys_user`; CREATE TABLE `sys_user` ( `id` int(10) NOT NULL, `username` varchar(50) DEFAULT NULL, `realname` varchar(50) DEFAULT NULL, `password` varchar(50) DEFAULT NULL, `createDate` date DEFAULT NULL, `lastLoginTime` date DEFAULT NULL, `enabled` int(5) DEFAULT NULL, `accountNonExpired` int(5) DEFAULT NULL, `accountNonLocked` int(5) DEFAULT NULL, `credentialsNonExpired` int(5) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_user -- ---------------------------- INSERT INTO `sys_user` VALUES ('1', 'kaico_admin', '張三', 'c2c92733a75333a4bac673632ff7519a', '2018-11-13', '2018-11-13', '1', '1', '1', '1'); INSERT INTO `sys_user` VALUES ('2', 'kaico_add', '小余', 'c2c92733a75333a4bac673632ff7519a', '2018-11-13', '2018-11-13', '1', '1', '1', '1'); -- ---------------------------- -- Table structure for sys_user_role -- ---------------------------- DROP TABLE IF EXISTS `sys_user_role`; CREATE TABLE `sys_user_role` ( `user_id` int(10) DEFAULT NULL, `role_id` int(10) DEFAULT NULL, KEY `FK_Reference_1` (`user_id`), KEY `FK_Reference_2` (`role_id`), CONSTRAINT `FK_Reference_2` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`id`), CONSTRAINT `FK_Reference_1` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of sys_user_role -- ---------------------------- INSERT INTO `sys_user_role` VALUES ('1', '1'); INSERT INTO `sys_user_role` VALUES ('2', '2');
maven依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.1.RELEASE</version> </parent> <dependencies> <!-- SpringBoot整合Web組件 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- springboot整合freemarker --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <!-->spring-boot 整合security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- springboot 整合mybatis框架 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!-- alibaba的druid數(shù)據(jù)庫連接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.9</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>
yml配置
# 配置freemarker
spring:
freemarker:
# 設(shè)置模板后綴名
suffix: .ftl
# 設(shè)置文檔類型
content-type: text/html
# 設(shè)置頁面編碼格式
charset: UTF-8
# 設(shè)置頁面緩存
cache: false
# 設(shè)置ftl文件路徑
template-loader-path:
- classpath:/templates
# 設(shè)置靜態(tài)文件路徑,js,css等
mvc:
static-path-pattern: /static/**
datasource:
name: test
url: jdbc:mysql://www.kaicostudy.com:3306/study_springSecurity
username: root
password: 123456
# druid 連接池
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
java代碼
實體類
// 用戶信息表 @Data public class UserEntity implements UserDetails { private Integer id; private String username; private String realname; private String password; private Date createDate; private Date lastLoginTime; private boolean enabled; private boolean accountNonExpired; private boolean accountNonLocked; private boolean credentialsNonExpired; // 用戶所有權(quán)限 private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } }
// 角色信息表 @Data public class RoleEntity { private Integer id; private String roleName; private String roleDesc; }
@Data public class PermissionEntity { private Integer id; // 權(quán)限名稱 private String permName; // 權(quán)限標(biāo)識 private String permTag; // 請求url private String url; }
mapper類
@Mapper public interface PermissionMapper { @Select(" select * from sys_permission ") List<PermissionEntity> findAllPermission(); }
@Mapper public interface UserMapper { /** * 根據(jù)用戶名稱查詢 * * @param userName * @return */ @Select(" select * from sys_user where username = #{userName}") UserEntity findByUsername(@Param("userName") String userName); /** * 查詢用戶的權(quán)限根據(jù)用戶查詢權(quán)限 * * @param userName * @return */ @Select(" select permission.* from sys_user user" + " inner join sys_user_role user_role" + " on user.id = user_role.user_id inner join " + "sys_role_permission role_permission on user_role.role_id = role_permission.role_id " + " inner join sys_permission permission on role_permission.perm_id = permission.id where user.username = #{userName};") List<PermissionEntity> findPermissionByUsername(@Param("userName") String userName); }
實現(xiàn)springSecurity的接口UserDetailsService
@Component @Slf4j public class MemberUserDetailsService implements UserDetailsService { @Autowired private UserMapper userMapper; /** * loadUserByUserName * * @param username * @return * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 1.根據(jù)該用戶名稱查詢在數(shù)據(jù)庫中是否存在 UserEntity userEntity = userMapper.findByUsername(username); if (userEntity == null) { return null; } // 2.查詢對應(yīng)的用戶權(quán)限 List<PermissionEntity> listPermission = userMapper.findPermissionByUsername(username); List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); listPermission.forEach(user -> { authorities.add(new SimpleGrantedAuthority(user.getPermTag())); }); log.info(">>>authorities:{}<<<", authorities); // 3.將該權(quán)限添加到security userEntity.setAuthorities(authorities); return userEntity; } }
密碼加密工具類
public class MD5Util { private static final String SALT = "kaico"; public static String encode(String password) { password = password + SALT; MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); } catch (Exception e) { throw new RuntimeException(e); } char[] charArray = password.toCharArray(); byte[] byteArray = new byte[charArray.length]; for (int i = 0; i < charArray.length; i++) byteArray[i] = (byte) charArray[i]; byte[] md5Bytes = md5.digest(byteArray); StringBuffer hexValue = new StringBuffer(); for (int i = 0; i < md5Bytes.length; i++) { int val = ((int) md5Bytes[i]) & 0xff; if (val < 16) { hexValue.append("0"); } hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } }
SecurityConfig配置類
@Component @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private MemberUserDetailsService memberUserDetailsService; /** * 添加授權(quán)賬戶 * * @param auth * @throws Exception */ @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 設(shè)置用戶賬號信息和權(quán)限 auth.userDetailsService(memberUserDetailsService).passwordEncoder(new PasswordEncoder() { @Override public String encode(CharSequence rawPassword) { //對密碼做加密 return MD5Util.encode((String) rawPassword); } /** * * @param charSequence 用戶輸入的密碼 * @param s 數(shù)據(jù)庫字段中加密好的密碼 * @return */ @Override public boolean matches(CharSequence charSequence, String s) { String rawPass = MD5Util.encode((String) charSequence); boolean result = rawPass.equals(s); return result; } }); } @Override protected void configure(HttpSecurity http) throws Exception { //配置權(quán)限 http.authorizeRequests().antMatchers("/addMember").hasAnyAuthority("addMember") .antMatchers("/addMember").hasAnyAuthority("addMember") .antMatchers("/delMember").hasAnyAuthority("delMember") .antMatchers("/updateMember").hasAnyAuthority("updateMember") .antMatchers("/showMember").hasAnyAuthority("showMember") .antMatchers("/login").permitAll() //放行登錄請求頁面 .antMatchers("/**").fullyAuthenticated() .and().formLogin().loginPage("/login").and().csrf().disable(); } }
整合完成,開始測試。
動態(tài)綁定數(shù)據(jù)庫所有權(quán)限
在上面代碼的基礎(chǔ)上實現(xiàn),上面是在代碼中配置請求路徑和權(quán)限標(biāo)識的綁定,現(xiàn)在改成在數(shù)據(jù)庫中動態(tài)配置。
SecurityConfig配置類
@Override protected void configure(HttpSecurity http) throws Exception { //配置權(quán)限 List<PermissionEntity> allPermission = permissionMapper.findAllPermission(); ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests(); allPermission.forEach((permission) -> { expressionInterceptUrlRegistry.antMatchers(permission.getUrl()). hasAnyAuthority(permission.getPermTag()); }); expressionInterceptUrlRegistry.antMatchers("/login").permitAll() .antMatchers("/**").fullyAuthenticated() .and().formLogin().loginPage("/login").and().csrf().disable(); }
到此這篇關(guān)于Springboot詳解整合SpringSecurity實現(xiàn)全過程的文章就介紹到這了,更多相關(guān)Springboot SpringSecurity內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Springboot安全框架整合SpringSecurity實現(xiàn)方式
- springboot整合security和vue的實踐
- springboot整合springsecurity與mybatis-plus的簡單實現(xiàn)
- SpringBoot如何整合Springsecurity實現(xiàn)數(shù)據(jù)庫登錄及權(quán)限控制
- SpringBoot整合SpringSecurityOauth2實現(xiàn)鑒權(quán)動態(tài)權(quán)限問題
- SpringBoot整合SpringSecurity實現(xiàn)JWT認證的項目實踐
- SpringBoot整合Security權(quán)限控制登錄首頁
- SpringBoot整合Spring?Security過濾器鏈加載執(zhí)行流程源碼分析(最新推薦)
- SpringBoot整合SpringSecurity和JWT和Redis實現(xiàn)統(tǒng)一鑒權(quán)認證
- SpringBoot整合SpringSecurity認證與授權(quán)
- SpringBoot整合Spring Security構(gòu)建安全的Web應(yīng)用
相關(guān)文章
Java后臺Controller實現(xiàn)文件下載操作
這篇文章主要介紹了Java后臺Controller實現(xiàn)文件下載操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10uploadify java實現(xiàn)多文件上傳和預(yù)覽
這篇文章主要為大家詳細介紹了java結(jié)合uploadify實現(xiàn)多文件上傳和預(yù)覽的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-10-10基于swagger參數(shù)與實體中參數(shù)不一致的原因分析
這篇文章主要介紹了基于swagger參數(shù)與實體中參數(shù)不一致的原因分析,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11