Spring Security 快速入门

Spring Security

http://docs.spring.io/spring-security/site/docs/4.2.2.RELEASE/reference/htmlsingle/#el-permission-evaluator

准备工作

使用Maven搭建SpringMVC项目

添加Spring Security支持

添加相关Jar

    4.2.2.RELEASE
    .....

    
    
      org.springframework.security
      spring-security-core
      ${spring.security.version}
    

    
      org.springframework.security
      spring-security-config
      ${spring.security.version}
    

    
      org.springframework.security
      spring-security-taglibs
      ${spring.security.version}
    

    
      org.springframework.security
      spring-security-web
      ${spring.security.version}
    

配置web.xml

添加filter DelegatingFilterProxy到web.xml

  
    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy
  
  
    springSecurityFilterChain
    /*
  

自定义WebSecurityConfig

@Configuration
@EnableWebSecurity
//添加annotation 支持,包括(prePostEnabled,securedEnabled...)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
                //所有用户可以访问"/resources"目录下的资源以及访问"/home"和favicon.ico
                .antMatchers("/resources/**", "/home","/**/favicon.ico").permitAll()

                //以"/admin"开始的URL,并需拥有 "ROLE_ADMIN" 角色权限,这里用hasRole不需要写"ROLE_"前缀,会自动加上
                .antMatchers("/admin/**").hasRole("ADMIN")
                //以"/admin"开始的URL,并需拥有 "ROLE_ADMIN" 角色权限和 "ROLE_DBA" 角色,这里不需要写"ROLE_"前缀;
                .antMatchers("/dba/**").access("hasRole('ADMIN') and hasRole('DBA')")

                //前面没有匹配上的请求,全部需要认证;
                .anyRequest().authenticated()

                .and()
                //指定登录界面,并且设置为所有人都能访问;
                .formLogin().loginPage("/login").permitAll()
                //如果登录失败会跳转到"/hello"
                .successForwardUrl("/hello")
                //如果登录失败会跳转到"/logout"
                //.failureForwardUrl("/logout")

                .and()
                .logout()
                .logoutUrl("/admin/logout") //指定登出的地址,默认是"/logout"
                .logoutSuccessUrl("/admin/index")   //登出后的跳转地址login?logout
                //.logoutSuccessHandler(logoutSuccessHandler) //自定义LogoutSuccessHandler,在登出成功后调用,如果被定义则logoutSuccessUrl()就会被忽略
                .invalidateHttpSession(true)  //定义登出时是否invalidate HttpSession,默认为true
                //.addLogoutHandler(logoutHandler) //添加自定义的LogoutHandler,默认会添加SecurityContextLogoutHandler
                .deleteCookies("usernameCookie","urlCookie") //在登出同时清除cookies

                .and().anonymous()
//                .and()
//                .exceptionHandling()
//                .authenticationEntryPoint(new BasicAuthenticationEntryPoint())
//                .accessDeniedHandler(accessDeniedHandler());  //测试发现accessDeniedHandler没生效,只会报Exception,没有跳转到实际page
                ;
    }

    @Autowired
    public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
                //指定密码加密形式,如数据库中用户密码为md5加密,这里就用Md5PasswordEncoder
                .passwordEncoder(passwordEncoder());
    }

    private Md5PasswordEncoder passwordEncoder() {
        return new Md5PasswordEncoder();
    }

    private AccessDeniedHandler accessDeniedHandler(){
        AccessDeniedHandlerImpl handler = new AccessDeniedHandlerImpl(); 
        handler.setErrorPage("/login");
        return handler;
    }
}

创建User

创建军User 类实现自 org.springframework.security.core.userdetails.UserDetails 接口,包含一组权限的集合 authorities。 
它和我们的领域类可能有部分属性重叠,可以把常用的部分字段存在里面。方便登录后调用。

public class User implements UserDetails {

    private String username;
    private String password;
    private List authorities;
    //....省略了其他需要用到字段,如做账号过期判断用到的一些字段,以及一些登录后常用的字段

    @Override
    public Collection getAuthorities() {
        return authorities;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        //...省略了判断逻辑
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        //...省略了判断逻辑
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        //...省略了判断逻辑
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

创建Authority

创建军Authority 类实现自 org.springframework.security.core.GrantedAuthority 接口,定义权限。 
getAuthority 方法只返回一个表示权限名称的字符串

public class Authority implements GrantedAuthority {

    private static final long serialVersionUID = 1L;

    private String authority;

    public Authority() {  }
    public Authority(String authority) {
        this.setAuthority(authority);
    }

    @Override
    public String getAuthority() {
        return this.authority;
    }
    public void setAuthority(String authority) {
        this.authority = authority;
    }
}

创建UserDetailsServiceImpl

创建军UserDetailsServiceImpl 类实现自 org.springframework.security.core.userdetails.UserDetailsService 接口。 
loadUserByUsername(String username) 方法根据用户名查询符合条件的用户,若没有找到符合条件的用户,必须抛出 UsernameNotFoundException 异常,而不能返回空。 
这里可以从数据库查询用户,这里只为实验写死了数据。

@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if(username.startsWith("a")){
            User user = new User(username,"e10adc3949ba59abbe56e057f20f883e",Arrays.asList(new Authority("ROLE_ADMIN")));
            return user;
        }
        if(username.startsWith("u")){
            User user = new User(username,"e10adc3949ba59abbe56e057f20f883e",Arrays.asList(new Authority("ROLE_USER")));
            return user;
        }
        if(username.startsWith("c")){
            User user = new User(username,"e10adc3949ba59abbe56e057f20f883e",Arrays.asList(new Authority("ROLE_ANONYMOUS")));
            return user;
        }
        if(username.startsWith("d")){
            User user = new User(username,"e10adc3949ba59abbe56e057f20f883e",
                    Arrays.asList(
                            new Authority("ROLE_ANONYMOUS"),
                            new Authority("ROLE_ADMIN"),
                            new Authority("ROLE_USER"),
                            new Authority("ROLE_DBA")));
            return user;
        }
        throw new UsernameNotFoundException("用户不存在!");
    }
}

前端代码

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path ;
%>



    Spring Security Example 



    
Invalid username and password.
You have been logged out.

home.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path ;
%>



    Spring Security Example


Welcome!

Click here to see a greeting.

hello.jsp

该页面包含一些security tgalib的使用,看代码:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
    String path = request.getContextPath();
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path ;
%>



    Hello World!


Hello !

the user has role 'ADMIN'
the user has role 'DBA'
the user has role 'USER'
This content will only be visible to users who are authorized to send requests to the "/admin" URL.

Controller

在WebSecurityConfig中配置了@EnableGlobalMethodSecurity(prePostEnabled = true) 
在Controller中可以直接使有注解的方式配置权限,和WebSecurityConfig中配置的权限是可以共存的。

    @PreAuthorize("hasAuthority('ROLE_ADMIN')")
    @RequestMapping(value = "/home")
    public String home(Model model,HttpServletRequest request){
        Authentication auth =(Authentication)request.getUserPrincipal();
        UserDetails userDetails = (UserDetails)auth.getPrincipal();
        auth.isAuthenticated();
        return "home";
    }

    @PreAuthorize("hasAnyRole('ADMIN','USER')")
    @RequestMapping(value = "/hello")
    public String hello(Model model,HttpServletRequest request){
        return "hello";
    }

可以通过HttpServletRequest取得当前用户状态和前面存在userDetail中的信息。 
@PreAuthorize(“hasAnyRole('ADMIN','USER')”)配置了hello方法必须至少有“ADMIN”或“USER”中的一个角色,这里不需要有ROLE_前缀,会自动加上。 
@PreAuthorize(“hasRole('ADMIN')”) 配置必须有“ADMIN”角色权限 
@PreAuthorize(“hasAuthority('ROLE_ADMIN')”) 配置必须有“ADMIN”角色权限,这里用的hasAuthority,所以需要带上ROLE_前缀 
@PreAuthorize 可以放在方法名上,也可以加在Controller名上。


权限表达式

Spring Security 快速入门_第1张图片

你可能感兴趣的:(Spring)