源码下载地址: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