SpringBoot 集成Spring security
阿新 • • 發佈:2018-05-13
oba java tails detail logout reat password rim res
Spring security作為一種安全框架,使用簡單,能夠很輕松的集成到springboot項目中,下面講一下如何在SpringBoot中集成Spring Security.使用gradle項目管理工具。
準備數據,
CREATE TABLE `user` ( `uid` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `roles` varchar(200) DEFAULT ‘USER‘, PRIMARYKEY (`uid`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; insert into `user` values(0,‘admin‘,‘admin‘,‘SUPER,role‘); //給不同個用戶配置不同的權限 insert into `user` values(1,‘role‘,‘role‘,‘role‘);
1:配置buildgradle,添加spring boot插件和spring security
buildscript { repositories { mavenCentral() } dependencies { classpath(‘org.springframework.boot:spring-boot-gradle-plugin:1.5.9.RELEASE‘) } } group "com.li" version "1.0-SNAPSHOT" apply plugin: "java" //java 插件 apply plugin: "org.springframework.boot" //spring boot 插件 apply plugin: "io.spring.dependency-management" apply plugin: "application" //應用 mainClassName = "com.li.SpringBootShrioApplication" sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { compile("org.springframework.boot:spring-boot-starter-web", "org.springframework.boot:spring-boot-starter-activemq", "org.springframework.boot:spring-boot-starter-test", "org.springframework.boot:spring-boot-starter-cache", "org.springframework.boot:spring-boot-devtools", "mysql:mysql-connector-java:5.1.35", ‘org.apache.commons:commons-lang3:3.4‘, ‘org.apache.commons:commons-pool2‘, "org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.0", ‘org.apache.logging.log4j:log4j-core:2.7‘, ‘org.springframework.boot:spring-boot-starter-security‘, ‘org.springframework.boot:spring-boot-starter-thymeleaf‘, ‘org.thymeleaf.extras:thymeleaf-extras-springsecurity4‘, //thymeleaf模板,集成 springsecurity4
‘net.sourceforge.nekohtml:nekohtml‘ ) testCompile group: ‘junit‘, name: ‘junit‘, version: ‘4.12‘ }
2:配置spring boot, application.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/springsecurity
username: root
password: 1367356
thymeleaf:
mode: LEGACYHTML5
cache: false
devtools:
restart:
enabled: true
server:
port: 8081
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml #Mapper所在的配置文件路徑,進行掃描
config-location: classpath:mybatis/mybatis-config.xml # mybaits-config文件
3:配置Spring Security
WebSecurityConfig.java 繼承 WebSecurityConfigurerAdapter.
當訪問項目時,安全管理器按照配置進行攔截,驗證通過才能訪問Controller相應的路徑。
package com.li.security; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; 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.crypto.bcrypt.BCryptPasswordEncoder; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled=true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Bean public BCryptPasswordEncoder bCryptPasswordEncoder() { return new BCryptPasswordEncoder(); } @Autowired MyUserDetailsService myUserDetailsService; @Bean public AuthenticationProvider authenticationProvider() { DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); authenticationProvider.setUserDetailsService(myUserDetailsService); authenticationProvider.setPasswordEncoder(this.bCryptPasswordEncoder()); return authenticationProvider; } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(myUserDetailsService).passwordEncoder(this.bCryptPasswordEncoder()); } @Override protected void configure(HttpSecurity http) throws Exception { // String[] s=null; http.csrf().disable() .authorizeRequests() .antMatchers("/user/settings").authenticated() // order matters .antMatchers("/", "/js/**", "/css/**","/avatar/**", "/images/**", "/fonts/**", "/bootstrap-select/**", "/bootstrap-datetimepicker/**", "/custom/**", "/daterangepicker/**", "/chartjs/**").permitAll() // these paths are configure not to require any authentication .antMatchers("/post/**").permitAll() // all posts are allowed to be viewed without authentication // .antMatchers("/user/**").permitAll() // all user profiles are allowed to be viewed without authentication .antMatchers("/category/**").permitAll() // all categories are allowed to be viewed without authentication .antMatchers("/user/registration").permitAll() .antMatchers("/avatar/**").permitAll() // temp .antMatchers("/visitor/**").permitAll() // temp // .antMatchers("/admin/**").hasAnyRole("SUPER","USER") // .antMatchers("/admin/**"). // .antMatchers("/admin/**").hasAnyRole(s) .anyRequest().authenticated() // every request requires the user to be authenticated .and() .formLogin() .loginPage("/user/login") .permitAll() // login URL can be accessed by anyone .and() .logout() .invalidateHttpSession(true) .clearAuthentication(true) .logoutSuccessUrl("/?logout") .permitAll(); } }
驗證:對訪問用戶進行驗證
package com.li.security; import com.li.dao.User; import com.li.service.UserService; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; @Service public class MyUserDetailsService implements UserDetailsService{ Logger logger = LogManager.getLogger(MyUserDetailsService.class); @Autowired private UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = this.userService.findUserByUserName(username); logger.debug(user.getUserName()+"密碼"+user.getPassword()); if(null == user) { throw new UsernameNotFoundException("Can‘t find user by username: " + username); } List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<>(); // grant roles to user for (String role : user.getRolesSet()) { logger.debug(role); grantedAuthorities.add(new SimpleGrantedAuthority(role)); //認證 } // user.setGrantedAuthorities(authorities); //用於登錄時 @AuthenticationPrincipal 標簽取值 return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), grantedAuthorities); //角色認證 } }
4: Controller ,Service,Dao層編寫
驗證通過,Controller對相應的http處理。可以在每個http上面指定相應的訪問權限
package com.li.controller; import com.li.dao.User; import com.li.service.UserService; import org.apache.catalina.servlet4preview.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.config.ResourceNotFoundException; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.validation.Valid; import java.util.Map; @Controller public class UserController { @Autowired UserService userService; @RequestMapping(value = "/", method = RequestMethod.GET) public String login() { System.out.println("home"); return "forum/home"; } @RequestMapping(value = "/user/login", method = RequestMethod.GET) public String displayLoginPage(Model model) { System.out.println("進入"); model.addAttribute("title", "用戶登陸"); return "forum/user-login"; //登錄界面,驗證沒通過。 } /** * 用戶註冊 * @param model * @return */ @RequestMapping(value = "/user/registration", method = RequestMethod.GET) public String showRegistrationPage(Model model) { System.out.println("registrationGet"); model.addAttribute("userDto", new User()); return "forum/user-registration"; //註冊頁面 } @RequestMapping(value = "/user/registration", method = RequestMethod.POST) //提交註冊 public String registerNewUser(@ModelAttribute("userDto") User user,BindingResult bindingResult, Model model, HttpServletRequest request) { System.out.println("registrationPost"); Map<String, Object> attributes = this.userService.registerUserAccount(user); model.addAllAttributes(attributes); return "forum/user-registration-result"; } @PreAuthorize("hasAuthority(‘SUPER‘)") //需要SUPER用戶才能通過該路徑,第一步通過配置驗證,沒有用戶登錄,將會攔截,讓用戶登錄,登錄成功,訪問該路徑時進行角色驗證。 @RequestMapping(value = "/admin/admin", method = RequestMethod.GET) public String deletePost() { return "admin/admin"; } }
Service
package com.li.service; import com.li.dao.User; import javax.servlet.http.HttpServletRequest; import java.util.Map; public interface UserService { public User findUserByUserName(String userName); public Map<String, Object> registerUserAccount(User user); }
SeriviceImpl,對用戶密碼加密存儲,
package com.li.service.impl; import com.li.dao.User; import com.li.dao.mapper.UserMapper; import com.li.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.sql.Timestamp; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.UUID; @Service public class UserServiceImpl implements UserService{ @Autowired BCryptPasswordEncoder bCryptPasswordEncoder; @Autowired UserMapper userMapper; @Override public User findUserByUserName(String userName) { return userMapper.findByUserName(userName); } @Override public Map<String, Object> registerUserAccount(User userDto) { Map<String, Object> attributes = new HashMap<>(); // save newly registered user User user = new User(); user.setPassword(bCryptPasswordEncoder.encode(userDto.getPassword())); //保存時應該將密碼編碼 user.setUserName(userDto.getUserName()); // user.activated(true); user.setRoles("USER"); // user.setConfirmationToken(UUID.randomUUID().toString()); // save new user and get number of affected row // logger.debug("用戶註冊"); int affectedRow = userMapper.save(user);// populate attributes String registrationResult = affectedRow == 1 ? "success" : "failure"; attributes.put("userRegistrationResult", registrationResult); return attributes; } }
DaoMapper
package com.li.dao.mapper; import com.li.dao.User; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @Mapper public interface UserMapper { public User findByUserName(String username); public int save(@Param("user") User user); }
普通User類
package com.li.dao; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** * 實驗室網站用戶 */ public class User { public int id; public String userName; public String password; public String roles; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRoles() { return roles; } public void setRoles(String roles) { this.roles = roles; } public Set<String> getRolesSet() { //獲取用戶權限 if (null == roles) { return null; } return Collections.unmodifiableSet( new HashSet<String>(Arrays.asList(getRoles().split(",")))); } public void addRole(String role) { String currRoles = this.getRoles(); if (null == currRoles || this.getRoles().contains(role)) { return; } this.setRoles(currRoles + "," + role); } @Override public String toString() { return "User{" + "id=" + id + ", userName=‘" + userName + ‘\‘‘ + ", password=‘" + password + ‘\‘‘ + ", roles=‘" + roles + ‘\‘‘ + ‘}‘; } }
5:編寫項目的前臺頁面,不同權限的頁面放到不同種類下面
SpringBoot 集成Spring security