源碼下載地址:http://git.oschina.net/alan_rcw/springboot-secrutiy/widgethtml
1、 整合Spring Security 在pom.xml中加入以下片斷: <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> 2、 配置Spring Security 幾乎全部配置都在下面這個文件中完成: @Configuration @EnableWebMvcSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsService customUserDetailsService;//code1 @Autowired @Qualifier("dataSource1") private DataSource dataSource1; //code2 @Override protected void configure(HttpSecurity http) throws Exception { //容許全部用戶訪問」/」和」/home」 http.authorizeRequests().antMatchers("/", "/home").permitAll() //其餘地址的訪問均需驗證權限 .anyRequest().authenticated() .and() .formLogin() //指定登陸頁是」/login」 .loginPage("/login") .permitAll() //登陸成功後可以使用loginSuccessHandler()存儲用戶信息,可選。 .successHandler(loginSuccessHandler())//code3 .and() .logout() //退出登陸後的默認網址是」/home」 .logoutSuccessUrl("/home") .permitAll() .invalidateHttpSession(true) .and() //登陸後記住用戶,下次自動登陸 //數據庫中必須存在名爲persistent_logins的表 //建表語句見code15 .rememberMe() .tokenValiditySeconds(1209600) //指定記住登陸信息所使用的數據源 .tokenRepository(tokenRepository());//code4 } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { //指定密碼加密所使用的加密器爲passwordEncoder() //須要將密碼加密後寫入數據庫 //code13 auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());//code5 //不刪除憑據,以便記住用戶 auth.eraseCredentials(false); } // Code5---------------------------------------------- @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(4); } // Code4---------------------------------------------- @Bean public JdbcTokenRepositoryImpl tokenRepository(){ JdbcTokenRepositoryImpl j=new JdbcTokenRepositoryImpl(); j.setDataSource(dataSource1); return j; } // Code3---------------------------------------------- @Bean public LoginSuccessHandler loginSuccessHandler(){ return new LoginSuccessHandler();//code6 } } code1---------------------------------------------- @Component public class CustomUserDetailsService implements UserDetailsService { @Autowired //數據庫服務類 private SUserService suserService;//code7 @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { //SUser對應數據庫中的用戶表,是最終存儲用戶和密碼的表,可自定義 //本例使用SUser中的email做爲用戶名: SUser user = suserService.findUserByEmail(userName); //code8 if (user == null) { throw new UsernameNotFoundException("UserName " + userName + " not found"); } // SecurityUser實現UserDetails並將SUser的Email映射爲username return new SecurityUser(user); //code9 } } Code2---------------------------------------------- @Configuration @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class }) public class MyConfiguration { @Bean public DataSource dataSource1() { org.springframework.jdbc.datasource.DriverManagerDataSource ds = new org.springframework.jdbc.datasource.DriverManagerDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver"); ds.setUrl("jdbc:mysql://localhost:3306/test"); ds.setUsername("root"); ds.setPassword("****"); return ds; } } Code6---------------------------------------------- //能夠在這裏將用戶登陸信息存入數據庫。 public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{ @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { //得到受權後可獲得用戶信息 可以使用SUserService進行數據庫操做 SUser userDetails = (SUser)authentication.getPrincipal(); //輸出登陸提示信息 System.out.println("管理員 " + userDetails.getEmail() + " 登陸"); System.out.println("IP :"+getIpAddress(request)); super.onAuthenticationSuccess(request, response, authentication); } public String getIpAddress(HttpServletRequest request){ String ip = request.getHeader("x-forwarded-for"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } return ip; } } Code7---------------------------------------------- @Service("suserService") public class SUserService { @Autowired private SUserRepository suserRepository;//code10 public List<SUser> findAll() { return suserRepository.findAll(); } public SUser create(SUser user) { return suserRepository.save(user); } public SUser findUserById(int id) { return suserRepository.findOne(id); } public SUser login(String email, String password) { return suserRepository.findByEmailAndPassword(email, password); } public SUser update(SUser user) { return suserRepository.save(user); } public void deleteUser(int id) { suserRepository.delete(id); } public SUser findUserByEmail(String email) { return suserRepository.findUserByEmail(email); } } Code8---------------------------------------------- @Entity @Table(name = "s_user", catalog = "test")//code11 public class SUser implements java.io.Serializable { private Integer id; private String name; private String email; private String password; private Date dob; private Set<SRole> SRoles = new HashSet<SRole>(0);// Code12 public SUser() { } public SUser(String name, String email, String password, Date dob, Set<SRole> SRoles) { this.name = name; this.email = email; this.password = password; this.dob = dob; this.SRoles = SRoles; } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "id", unique = true, nullable = false) public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } @Column(name = "name", length = 20) public String getName() { return this.name; } public void setName(String name) { this.name = name; } @Column(name = "email", length = 20) public String getEmail() { return this.email; } public void setEmail(String email) { this.email = email; } @Column(name = "password", length = 20) public String getPassword() { return this.password; } public void setPassword(String password) { this.password = password; } @Temporal(TemporalType.DATE) @Column(name = "dob", length = 10) public Date getDob() { return this.dob; } public void setDob(Date dob) { this.dob = dob; } @OneToMany(fetch = FetchType.EAGER, mappedBy = "SUser") public Set<SRole> getSRoles() { return this.SRoles; } public void setSRoles(Set<SRole> SRoles) { this.SRoles = SRoles; } } Code9---------------------------------------------- public class SecurityUser extends SUser implements UserDetails { private static final long serialVersionUID = 1L; public SecurityUser(SUser suser) { if(suser != null) { this.setId(suser.getId()); this.setName(suser.getName()); this.setEmail(suser.getEmail()); this.setPassword(suser.getPassword()); this.setDob(suser.getDob()); this.setSRoles(suser.getSRoles()); } } @Override public Collection<? extends GrantedAuthority> getAuthorities() { Collection<GrantedAuthority> authorities = new ArrayList<>(); Set<SRole> userRoles = this.getSRoles(); if(userRoles != null) { for (SRole role : userRoles) { SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getName()); authorities.add(authority); } } return authorities; } @Override public String getPassword() { return super.getPassword(); } @Override public String getUsername() { return super.getEmail(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } } Code10---------------------------------------------- public interface SUserRepository extends JpaRepository<SUser, Integer> { @Query("select u from SUser u where u.email=?1 and u.password=?2") SUser login(String email, String password); SUser findByEmailAndPassword(String email, String password); SUser findUserByEmail(String email); } Code11---------------------------------------------- SUser對應的表和角色表,一個都不能少 CREATE TABLE `s_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `email` varchar(20) DEFAULT NULL, `password` varchar(60) DEFAULT NULL, `dob` date DEFAULT NULL, PRIMARY KEY (`id`) ) CREATE TABLE `s_role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `uid` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `userrole` (`uid`), CONSTRAINT `userrole` FOREIGN KEY (`uid`) REFERENCES `s_user` (`id`) ) Code12---------------------------------------------- @Entity @Table(name = "s_role", catalog = "test") public class SRole implements java.io.Serializable { private Integer id; private SUser SUser; private String name; public SRole() { } public SRole(SUser SUser) { this.SUser = SUser; } public SRole(SUser SUser, String name) { this.SUser = SUser; this.name = name; } @Id @GeneratedValue(strategy = IDENTITY) @Column(name = "id", unique = true, nullable = false) public Integer getId() { return this.id; } public void setId(Integer id) { this.id = id; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "uid", nullable = false) public SUser getSUser() { return this.SUser; } public void setSUser(SUser SUser) { this.SUser = SUser; } @Column(name = "name", length = 20) public String getName() { return this.name; } public void setName(String name) { this.name = name; } } Code13---------------------------------------------- @SpringBootApplication public class Application { @SuppressWarnings("unchecked") public static void main(String[] args) { SpringApplication app=new SpringApplication(Application.class); Appctx.ctx=app.run(args);//將密碼加密 必須保證數據庫s_user中有id爲1的用戶//code14 SUserService suserService = (SUserService) Appctx.ctx.getBean("suserService"); SUser su= suserService.findUserById(1); BCryptPasswordEncoder bc=new BCryptPasswordEncoder(4); su.setPassword(bc.encode("111111")); suserService.update(su); } Code14---------------------------------------------- public class Appctx { public static ApplicationContext ctx=null; public static Object getObject(String string){ return ctx.getBean(string); } } Code15---------------------------------------------- //請勿手工寫入數據 供remember-me功能使用 CREATE TABLE `persistent_logins` ( `username` varchar(64) NOT NULL, `series` varchar(64) NOT NULL, `token` varchar(64) NOT NULL, `last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`series`) ) Code15---------------------------------------------- public interface SRoleRepository extends JpaRepository<SRole,Integer> { } 3、 Html及controller index.html: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>Insert title here</title> </head> <body> Welcome to Spring technology page! </body> </html> hello.html <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <head> <title>Hello World!</title> </head> <body> <h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1> <form th:action="@{/logout}" method="post"> <input type="submit" value="Sign Out"/> </form> </body> </html> home.html <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <head> <title>Spring Security Example</title> </head> <body> <h1>Welcome!</h1> <p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p> </body> </html> login.html 本頁中 username password remember-me三個控件請勿更名。 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"> <head> <title>Spring Security Example </title> </head> <body> <div th:if="${param.error}"> Invalid username and password. </div> <div th:if="${param.logout}"> You have been logged out. </div> <div th:if="${#httpServletRequest.remoteUser != null}"> <p th:text="${#httpServletRequest.remoteUser}"> sample_user </p> </div> <form th:action="@{/login}" method="post"> <div><label> User Name : <input type="text" name="username"/> </label></div> <div><label> Password: <input type="password" name="password"/> </label></div> <div><input type="submit" value="Sign In"/></div> <input type="checkbox" name="remember-me" value="true" th:checked="checked"/><p>Remember me</p> </form> </body> </html> Controller: @Controller @RequestMapping("/") public class GreetingController { @RequestMapping("/home") public String home() { return "home"; } @RequestMapping("/hello") public String hello() { SecurityContext ctx = SecurityContextHolder.getContext(); Authentication auth = ctx.getAuthentication(); if(auth.getPrincipal() instanceof UserDetails) { SUser user = (SUser)auth.getPrincipal(); System.out.println(user.getEmail()); } //本段代碼演示如何獲取登陸的用戶資料 return "hello"; } @RequestMapping("/") public String root() { //如不進行此項配置,從login登陸成功後,會提示找不網頁 return "index"; } }
4、 構建及運行順序
1. 首先創建s_user s_role表,並向表中寫入數據
2. 創建SUserService SUserRepository SUser SRoleRepository SRole類
3. 運行程序,將s_user中用戶的密碼加密
4. 如三中所述,配置Spring Security
5. 運行,訪問http://localhost:8080/hello,系統出現以下界面:
用戶名輸入useremail 密碼輸入111111,點sign in則進入hello.html
重啓瀏覽器,再訪問http://localhost:8080/hello,則無需登陸,直接到達。
在hello頁面點sign out後,則返回home頁面,退出了登陸。java