旅游后台项目——SSM权限操作(Spring Security)

SSM权限操作

数据库与表结构

用户表

旅游后台项目——SSM权限操作(Spring Security)

角色表

旅游后台项目——SSM权限操作(Spring Security)

用户与角色之间是多对多关系,通过user_role表来描述其关联,在实体类中User中存在List,在Role中有List。而角色与权限之间也存在关系。

资源权限表

旅游后台项目——SSM权限操作(Spring Security)

权限资源与角色是多对多关系,使用role_permission表来描述。在实体类Permission中存在List。在Role类中有List

Spring Security概述

Spring Security介绍

Spring Security 的前身是 Acegi Security ,是 Spring 项目组中用来提供安全认证服务的框架。(https://projects.spring.io/spring-security/) Spring Security 为基于J2EE企业应用软件提供了全面安全服务。特别是使用领先的J2EE解决方案-Spring框架开发的企业软件项目。人们使用Spring Security有很多种原因,不过通常吸引他们的是在J2EE Servlet规范或EJB规范中找不到典型企业应用场景的解决方案。 特别要指出的是他们不能再WAR 或 EAR 级别进行移植。这样,如果你更换服务器环境,就要,在新的目标环境进行大量的工作,对你的应用系统进行重新配 置安全。使用Spring Security 解决了这些问题,也为你提供很多有用的,完全可以指定的其他安全特性。 安全包括两个主要操作。

  • “认证”,是为用户建立一个他所声明的主体。主题一般式指用户,设备或可以在你系统中执行动作的其他系统。
  • “授权”指的是一个用户能否在你的应用中执行某个操作,在到达授权判断之前,身份的主题已经由 身份验证过程建立了。

这些概念是通用的,不是Spring Security特有的。在身份验证层面,Spring Security广泛支持各种身份验证模式,这些验证模型绝大多数都由第三方提供,或则正在开发的有关标准机构提供的,例如 Internet Engineering TaskForce.作为补充,Spring Security 也提供了自己的一套验证功能。

Spring Security 目前支持认证一体化如下认证技术: HTTP BASIC authentication headers (一个基于IEFT RFC 的标准) HTTP Digest authentication headers (一个基于IEFT RFC 的标准) HTTP X.509 client certifificate exchange(一个基于IEFT RFC 的标准) LDAP (一个非常常见的跨平台认证需要做法,特别是在大环境) Form-basedauthentication (提供简单用户接口的需求) OpenID authentication Computer Associates Siteminder JA-SIGCentral Authentication Service (CAS,这是一个流行的开源单点登录系统) Transparent authentication context propagation for Remote Method Invocation and HttpInvoker (一个Spring远程调用协议)

Maven依赖

<!--  权限  -->
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-web</artifactId>
      <version>5.0.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-config</artifactId>
      <version>5.0.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-core</artifactId>
      <version>5.0.1.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.security</groupId>
      <artifactId>spring-security-taglibs</artifactId>
      <version>5.0.1.RELEASE</version>
    </dependency>

Spring Security快速入门

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>spring_security_demo</groupId>
 <artifactId>SpringSecurity_quickStart</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <packaging>war</packaging>
 <properties>
 <spring.version>5.0.2.RELEASE</spring.version>
 <spring.security.version>5.0.1.RELEASE</spring.security.version>
 </properties>
 <dependencies>
     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-core</artifactId>
         <version>${spring.version}</version>
     </dependency>
     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-web</artifactId>
         <version>${spring.version}</version>
     </dependency>
     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-webmvc</artifactId>
         <version>${spring.version}</version>
     </dependency>
     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-context-support</artifactId>
         <version>${spring.version}</version>
     </dependency>
     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-test</artifactId>
         <version>${spring.version}</version>
     </dependency>
     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-jdbc</artifactId>
         <version>${spring.version}</version>
     </dependency>
     <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-web</artifactId>
         <version>${spring.security.version}</version>
     </dependency>
     <dependency>
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-config</artifactId>
         <version>${spring.security.version}</version>
     </dependency>
     <dependency>
         <groupId>javax.servlet</groupId>
         <artifactId>javax.servlet-api</artifactId>
         <version>3.1.0</version>
         <scope>provided</scope>
     </dependency>
 </dependencies>
 <build>
     <plugins>
         <!-- java编译插件 -->
         <plugin>
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-compiler-plugin</artifactId>
             <version>3.2</version>
             <configuration>
                 <source>1.8</source>
                 <target>1.8</target>
                 <encoding>UTF-8</encoding>
             </configuration>
         </plugin>
     	 <plugin>
             <groupId>org.apache.tomcat.maven</groupId>
             <artifactId>tomcat7-maven-plugin</artifactId>
             <configuration>
                 <!-- 指定端口 -->
                 <port>8080</port>
                 <!-- 请求路径 -->
                 <path>/</path>
             </configuration>
         </plugin>
     </plugins>
 </build>
</project>
     

web.xml

<context-param>
 <param-name>contextConfigLocation</param-name>
 <param-value>classpath:spring-security.xml</param-value>
 </context-param>
 <listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <filter>
 <filter-name>springSecurityFilterChain</filter-name>
 <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 </filter>
 <filter-mapping>
 <filter-name>springSecurityFilterChain</filter-name>
 <url-pattern>/*</url-pattern>
 </filter-mapping>

spring security配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:security="http://www.springframework.org/schema/security"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd 
 http://www.springframework.org/schema/security 
 http://www.springframework.org/schema/security/spring-security.xsd">
 <security:http auto-config="true" use-expressions="false">
 <!-- intercept-url定义一个过滤规则 pattern表示对哪些url进行权限控制,ccess属性表示在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的角色列表,请求的用户只需拥有其中的一个角色就能成功访问对应的URL -->
     <security:intercept-url pattern="/**" access="ROLE_USER" />
     <!-- auto-config配置后,不需要在配置下面信息 <security:form-login /> 定义登录表单信息
        <security:http-basic/> <security:logout /> -->
 </security:http>
    <security:authentication-manager>
         <security:authentication-provider>
              <security:user-service>
                   <security:user name="user" password="{noop}user"
                                 authorities="ROLE_USER" />
                   <security:user name="admin" password="{noop}admin"
                                 authorities="ROLE_ADMIN" />
              </security:user-service>
         </security:authentication-provider>
     </security:authentication-manager>
</beans>

我们在webapp下创建一个index.html页面,在页面中任意写些内容。

当我们访问index.html页面时发现会弹出登录窗口,可能你会奇怪,我们没有建立下面的登录页面,为什么SpringSecurity会跳到上面的登录页面呢?这是我们设置http的auto-confifig=”true”时Spring Security自动为我们生成的。

使用自定义页面

spring-security.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:security="http://www.springframework.org/schema/security"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/security
 http://www.springframework.org/schema/security/spring-security.xsd">
 <!-- 配置不过滤的资源(静态资源及登录相关) -->
 <security:http security="none" pattern="/login.html" />
 <security:http security="none" pattern="/failer.html" />
 <security:http auto-config="true" use-expressions="false">
     <!-- 配置资料连接,表示任意路径都需要ROLE_USER权限 -->
     <security:intercept-url pattern="/**" access="ROLE_USER" />
     <!-- 自定义登陆页面,login-page 自定义登陆页面 authentication-failure-url 用户权限校验失败之后才会跳转到这个页面,如果数据库中没有这个用户则不会跳转到这个页面。default-target-url 登陆成功后跳转的页面。 注:登陆页面用户名固定 username,密码password,action:login -->
     <security:form-login login-page="/login.html"
     login-processing-url="/login" username-parameter="username"
     password-parameter="password" authentication-failure-url="/failer.html"
     default-target-url="/success.html" 
     />
     <!-- 登出, invalidate-session 是否删除session logout-url:登出处理链接 logout-successurl:登出成功页面
     注:登出操作 只需要链接到 logout即可登出当前用户 -->
     <security:logout invalidate-session="true" logout-url="/logout"
     logout-success-url="/login.jsp" />
     <!-- 关闭CSRF,默认是开启的 -->
     <security:csrf disabled="true" />
 </security:http>
 <security:authentication-manager>
     <security:authentication-provider>
         <security:user-service>
             <security:user name="user" password="{noop}user"
             authorities="ROLE_USER" />
             <security:user name="admin" password="{noop}admin"
             authorities="ROLE_ADMIN" />
         </security:user-service>
     </security:authentication-provider>
 </security:authentication-manager>
</beans>

login.html

 <!DOCTYPE html>
 <html>
 <head>
 <meta charset="UTF-8">
 <title>Insert title here</title>
 </head>
 <body>
     <form action="login" method="post">
         <table>
             <tr>
             	<td>用户名:</td>
             <td>
                 <input type="text" name="username" /></td>
             </tr>
             <tr>
             	<td>密码:</td>
             <td>
                 <input type="password" name="password" /></td>
             </tr>
             <tr>
             <td colspan="2" align="center">
                 <input type="submit" value="登录" />
             	 <input type="reset" value="重置" /></td>
             </tr>
         </table>
     </form>
 </body>
 </html>

success.html

<!DOCTYPE html>
 <html>
 <head>
 <meta charset="UTF-8">
 <title>Insert title here</title>
 </head>
 <body>
 success html<br>
     <a href="logout">退出</a>
 </body>
 </html>

failer.html

<!DOCTYPE html>
 <html>
 <head>
 <meta charset="UTF-8">
 <title>Insert title here</title>
 </head>
 <body>登录失败
 </body>
 </html>

Spring Security使用数据库认证

在Spring Security中如果想要使用数据进行认证操作,有很多种操作方式,这里我们介绍使用UserDetails、UserDetailsService来完成操作。

UserDetails

public interface UserDetails extends Serializable { 
     Collection<? extends GrantedAuthority> getAuthorities();
     String getPassword(); 
     String getUsername(); 
     boolean isAccountNonExpired(); 
     boolean isAccountNonLocked();
     boolean isCredentialsNonExpired();
     boolean isEnabled();
}

UserDetails是一个接口,我们可以认为UserDetails作用是于封装当前进行认证的用户信息,但由于其是一个接口,所以我们可以对其进行实现,也可以使用Spring Security提供的一个UserDetails的实现类User来完成操作

User

public class User implements UserDetails, CredentialsContainer {
     private String password;
     private final String username;
     private final Set<GrantedAuthority> authorities;
     private final boolean accountNonExpired; //帐户是否过期
     private final boolean accountNonLocked; //帐户是否锁定
     private final boolean credentialsNonExpired; //认证是否过期
     private final boolean enabled; //帐户是否可用
}

UserDetailsService

public interface UserDetailsService {
 	UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}

上面将UserDetails与UserDetailsService做了一个简单的介绍,那么我们具体如何完成Spring Security的数据库认证操作哪,我们通过用户管理中用户登录来完成Spring Security的认证操作。

用户管理

用户登录

spring security的配置

 <!-- 切换成数据库中的用户名和密码 -->
    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userService">

            <security:password-encoder ref="passwordEncoder"/>
        </security:authentication-provider>
    </security:authentication-manager>

Service

@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
     @Autowired
     private IUserDao userDao;
     @Override
     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
         UserInfo userInfo = userDao.findByUsername(username);
         List<Role> roles = userInfo.getRoles();
         List<SimpleGrantedAuthority> authoritys = getAuthority(roles);
         User user = new User(userInfo.getUsername(), "{noop}" + userInfo.getPassword(),
         userInfo.getStatus() == 0 ? false : true, true, true, true, authoritys);
         return user;
     }
    
     private List<SimpleGrantedAuthority> getAuthority(List<Role> roles) {
         List<SimpleGrantedAuthority> authoritys = new ArrayList();
         for (Role role : roles) {
         	authoritys.add(new SimpleGrantedAuthority(role.getRoleName()));
         }
         return authoritys;
     }
}

UserDao

public interface IUserDao {
     @Select("select * from user where id=#{id}")
     public UserInfo findById(Long id) throws Exception;
    
     @Select("select * from user where username=#{username}")
     @Results({
         @Result(id = true, property = "id", column = "id"),
         @Result(column = "username", property = "username"),
         @Result(column = "email", property = "email"), 
         @Result(column = "password", property = "password"),
         @Result(column = "phoneNum", property = "phoneNum"), 
         @Result(column = "status", property = "status"),
         @Result(column = "id", property = "roles", javaType = List.class, many = 
         		@Many(select = "com.itheima.ssm.dao.IRoleDao.findRoleByUserId")) })
     public UserInfo findByUsername(String username);
 }

用户退出

使用spring security完成用户退出,非常简单

配置

<security:logout invalidate-session="true" logout-url="/logout.do" logout-success-url="/login.jsp" />

页面中

<a href="${pageContext.request.contextPath}/logout.do" class="btn btn-default btn-flat">注销</a>

用户查询

UserController

@Controller
@RequestMapping("/user")
public class UserControlller {
 
     @RequestMapping("/findAll.do")
     public ModelAndView findAll() throws Exception {
     	 List<UserInfo> users = userService.findAll();
         ModelAndView mv = new ModelAndView();
         mv.addObject("userlist", users);
         mv.setViewName("user-list");
         return mv;
     }
}

Dao

@Select("select * from user")
 public List<UserInfo> findAll();

用户添加

UserController

@Controller
@RequestMapping("/user")
public class UserControlller {
     @Autowired
     private IUserService userService;

     @RequestMapping("/save.do")
     public String save(UserInfo user) throws Exception {
         userService.save(user);
         return "redirect:findAll.do";
     }
 }

Service

@Service("userService")
@Transactional
public class UserServiceImpl implements IUserService {
     @Autowired
     private IUserDao userDao;
     @Autowired
     private PasswordEncoder passwordEncoder;
     @Override
     public void save(UserInfo user) throws Exception {
         user.setPassword(passwordEncoder.encode(user.getPassword()));
         userDao.save(user);
     }
}

前期我们的用户密码没有加密,现在添加用户时,我们需要对用户密码进行加密

<!-- 配置加密类 -->
    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

Dao

@Insert("insert into user(email,username,password,phoneNum,status) value(#{email},#{username},#{password},#{phoneNum},#{status})") 
public void save(UserInfo user) throws Exception;

用户详情

用户详情页面user-show.jsp

注意:需要添加js

$("#collapse-table").treetable({ expandable : true });

UserController

@Controller 
@RequestMapping("/user") 
public class UserControlller { 
    @Autowired 
    private IUserService userService;
    
	@RequestMapping("/findById.do")
    public ModelAndView findById(@RequestParam(name = "id", required = true) String id) throws Exception {
        Users user = userService.findById(id);
        ModelAndView mv = new ModelAndView();
        mv.addObject("user", user);
        mv.setViewName("user-show");
        return mv;
    }
}

Dao

@Select("select * from users where id=#{id}")
@Results({ @Result(id = true, property = "id", column = "id"), @Result(column = "username", property = "username"),
        @Result(column = "email", property = "email"), @Result(column = "password", property = "password"),
        @Result(column = "phoneNum", property = "phoneNum"), @Result(column = "status", property = "status"),
        @Result(column = "id", property = "roles", javaType = List.class, many =
        @Many(select = "com.sibd.travel.mapper.RoleMapper.findRoleByUserId")) })
Users findById(String id);
@Select("select * from role where id in( select roleId from user_role where userId=#{userId})") 
    @Results( 
    { 
        @Result(id=true,column="id",property="id"), 
        @Result(column="roleName",property="roleName"), 
        @Result(column="roleDesc",property="roleDesc"), 
  @Result(column="id",property="permissions",javaType=List.class,many=@Many(select="com.itheima.ssm.dao.IPermissionDao.findByRoleId")) 
    }) 
public List<Role> findRoleByUserId(Long userId);

我们需要将用户的所有角色及权限查询出来所以需要调用IRoleDao中的findRoleByUserId,而在IRoleDao中需要调用IPermissionDao的findByRoleId

@Select("select * from permission where id in (select permissionId from role_permission where roleId=#{roleId})") 
public List<Permission> findByRoleId(Long roleId);

角色管理

角色查询

RoleControlller

@RequestMapping("/role") 
@Controller 
public class RoleController { 
    @Autowired 
    private IRoleService roleService; 
    @RequestMapping("/findAll.do") 
    public ModelAndView findAll() throws Exception { 
        List<Role> roleList = roleService.findAll(); 
        ModelAndView mv = new ModelAndView(); 
        mv.addObject("roleList", roleList); 
        mv.setViewName("role-list"); 
        return mv; 
    } 
}

Dao

@Select("select * from role") 
public List<Role> findAll();

角色添加

RoleController

@RequestMapping("/role") 
@Controller 
public class RoleController { 
    @Autowired 
    private IRoleService roleService; 
    @RequestMapping("/save.do") 
    public String save(Role role) { 
        roleService.save(role); 
        return "redirect:findAll.do"; 
    } 
}

Dao

@Insert("insert into role(roleName,roleDesc) value(#{roleName},#{roleDesc})") 
public void save(Role role);

资源权限管理

资源权限查询

PermissionController

@RequestMapping("/permission") 
@Controller 
public class PermissionController {
	@Autowired 
    private IPermissionService permissionService; 
    @RequestMapping("/findAll.do") 
    public ModelAndView findAll() throws Exception { 
        List<Permission> permissionList = permissionService.findAll(); 
        ModelAndView mv = new ModelAndView(); 
        mv.addObject("permissionList", permissionList); 
        mv.setViewName("permission-list"); 
        return mv; 
    } 
}

Dao

@Select("select * from permission") 
public List<Permission> findAll();

资源权限添加

PermissionController

@RequestMapping("/permission") 
@Controller 
public class PermissionController { 
    @Autowired 
    private IPermissionService permissionService; 
    @RequestMapping("/save.do") 
    public String save(Permission p) throws Exception { 
        permissionService.save(p); 
        return "redirect:findAll.do"; 
    } 
}

Dao

@Insert("insert into permission(permissionName,url) value(#{permissionName},#{url})") 
public void save(Permission p);

权限关联与控制

用户角色关联

用户与角色之间是多对多关系,我们要建立它们之间的关系,只需要在中间表user_role插入数据即可。

用户角色关联相关页面

在user-list.jsp页面上添加链接

<a href="${pageContext.request.contextPath}/user/findUserByIdAndAllRole.do?id=${user.id}" class="btn bg-olive btn-xs">添加角色</a>

展示可以添加角色的页面user-role-add.jsp

UserController

findUserByIdAndAllRole(Long id)方法

此方法用于查找要操作的用户及可以添加的角色,参数是要操作的用户id

@RequestMapping("/findUserByIdAndAllRole.do") 
public ModelAndView findUserByIdAndAllRole(Long id) throws Exception { 
    UserInfo user = userService.findById(id); 
    List<Role> roleList = roleService.findOtherRole(id); 
    ModelAndView mv = new ModelAndView(); 
    mv.addObject("user", user); 
    mv.addObject("roleList", roleList); 
    mv.setViewName("user-role-add"); 
    return mv; 
}

调用UserService的findById方法获取要操作的User

调用RoleService的findOtherRole方法用于获取可以添加的角色信息

  • addRoleToUser(Long userId,Long[] ids)方法

这些方法用于在用户与角色之间建立关系,参数userId代表要操作的用户id,参数ids代表的是角色id数组

@RequestMapping("/addRoleToUser.do") 
public String addRoleToUser(Long userId, Long[] ids) throws Exception { 
    userService.addRoleToUser(userId,ids); 
    return "redirect:findAll.do"; 
}

Dao

//用于查找可以添加的角色
@Select("select * from role where id not in( select roleId from user_role where userId=#{id})") 
public List<Role> findOtherRole(Long id);
//用于添加用户与角色关系
@Insert("insert into user_role(userId,roleId) value(#{userId},#{roleId})") 
public void addRoleToUser(@Param("userId") Long userId, @Param("roleId") Long roleId);

角色权限关联

角色与权限之间是多对多关系,我们要建立它们之间的关系,只需要在中间表role_permission插入数据即可。

角色权限关联相关页面

在role-list.jsp页面上添加链接

<a href="${pageContext.request.contextPath}/role/findRoleByIdAndAllPermission.do?id=${role.id}" class="btn bg-olive btn-xs">添加权限</a>

展示可以添加权限的页面roe-permission-add.jsp

RoleController

  • findRoleByIdAndAllPermission(Long roleId)方法

此方法用于查找要操作的角色及可以添加的权限,参数是要操作的角色id

@RequestMapping("/findRoleByIdAndAllPermission.do") 
public ModelAndView findRoleByIdAndAllPermission(@RequestParam(name = "id", required = true) Long roleid) throws Exception { 
    ModelAndView mv = new ModelAndView(); 
    Role role = roleService.findById(roleid); 
    mv.addObject("role", role); 
    List<Permission> permissionList = 
    permissionService.findOtherPermission(roleid); 
    mv.addObject("permissionList", permissionList); 
    mv.setViewName("role-permission-add"); 
    return mv; 
}

调用RoleService的findById方法获取要操作的Role

调用PermissionService的findOtherPermission方法用于获取可以添加的权限信息

  • addPermissionToRole(Long roleId,Long[] ids)方法

些方法用于在角色与权限之间建立关系,参数roleId代表要操作的角色id,参数permissionIds代表的是权限id数组

@RequestMapping("/addPermissionToRole.do") 
public String addPermissionToRole(@RequestParam(name = "roleId") Long roleId, @RequestParam(name = "ids") Long[] permissionIds) throws Exception { 
    roleService.addPermissionToRole(roleId, permissionIds); 
    return "redirect:findAll.do"; 
}

Dao

//用于查找可以添加的权限
@Select("select * from permission where id not in (select permissionId from role_permission where roleId=#{roleId})") 
public List<Permission> findOtherPermission(Long roleid);
//用于绑定角色与权限的关系
@Insert("insert into role_permission (roleId,permissionId) value (#{roleId},#
{permissionId})") 
public void addPermissionToRole(@Param("roleId") Long roleId,@Param("permissionId") Long permissionId);

服务器端方法级权限控制

在服务器端我们可以通过Spring security提供的注解对方法来进行权限控制。Spring Security在方法的权限控制上支持三种类型的注解,JSR-250注解、@Secured注解和支持表达式的注解,这三种注解默认都是没有启用的,需要单独通过global-method-security元素的对应属性进行启用

开启注解使用

  • 配置文件
<security:global-method-security jsr250-annotations=*"enabled"*/> 
<security:global-method-security secured-annotations=*"enabled"*/> 
<security:global-method-security pre-post-annotations=*"disabled"*/>
  • 注解开启

@EnableGlobalMethodSecurity :Spring Security默认是禁用注解的,要想开启注解,需要在继承

WebSecurityConfigurerAdapter的类上加@EnableGlobalMethodSecurity注解,并在该类中将

AuthenticationManager定义为Bean。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}

JSR-250注解

  • @RolesAllowed表示访问对应方法时所应该具有的角色

  • 示例:
    @RolesAllowed({"USER", "ADMIN"}) 该方法只要具有"USER", "ADMIN"任意一种权限就可以访问。这里可以省略前缀ROLE_,实际的权限可能是ROLE_ADMIN
    
  • @PermitAll表示允许所有的角色进行访问,也就是说不进行权限控制

  • @DenyAll是和PermitAll相反的,表示无论什么角色都不能访问

支持表达式的注解

  • @PreAuthorize 在方法调用之前,基于表达式的计算结果来限制对方法的访问
示例:
@PreAuthorize("#userId == authentication.principal.userId or hasAuthority(‘ADMIN’)") void changePassword(@P("userId") long userId ){ } 
这里表示在changePassword方法执行之前,判断方法参数userId的值是否等于principal中保存的当前用户的userId,或者当前用户是否具有ROLE_ADMIN权限,两种符合其一,就可以访问该方法。
  • 常见内置表达式https://docs.spring.io/spring-security/site/docs/4.0.1.RELEASE/reference/htmlsingle/#el-common-built-in
  • @PostAuthorize 允许方法调用,但是如果表达式计算结果为false,将抛出一个安全性异常
示例:
@PostAuthorize 
User getUser("returnObject.userId == authentication.principal.userId or hasPermission(returnObject, 'ADMIN')");
  • @PostFilter 允许方法调用,但必须按照表达式来过滤方法的结果

  • @PreFilter 允许方法调用,但必须在进入方法之前过滤输入值

@Secured注解

  • @Secured注解标注的方法进行权限控制的支持,其值默认为disabled。
示例:
 @Secured("IS_AUTHENTICATED_ANONYMOUSLY") 
 public Account readAccount(Long id); 
 @Secured("ROLE_TELLER")

@Secured注解是用来定义业务方法的安全配置。在需要安全[角色/权限等]的方法上指定 @Secured,并且只有那些角色/权限的用户才可以调用该方法。

@Secured缺点(限制)就是不支持Spring EL表达式。不够灵活。并且指定的角色必须以ROLE_开头,不可省略。该注解功能要简单的多,默认情况下只能基于角色(默认需要带前缀 ROLE_)集合来进行访问控制决策。该注解的机制是只要其声明的角色集合(value)中包含当前用户持有的任一角色就可以访问。也就是 用户的角色集合和 @Secured 注解的角色集合要存在非空的交集。 不支持使用 SpEL 表达式进行决策。

页面端标签控制权限

在jsp页面中我们可以使用spring security提供的权限标签来进行权限控制

maven导入

<dependency> 
     <groupId>org.springframework.security</groupId> 
     <artifactId>spring-security-taglibs</artifactId> 
     <version>version</version> 
</dependency>

页面导入

<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>

常用标签

在jsp中我们可以使用以下三种标签,其中authentication代表的是当前认证对象,可以获取当前认证对象信息,例如用户名。其它两个标签我们可以用于权限控制

authentication

authentication代表的是当前认证对象,可以获取当前认证对象信息

<security:authentication property="" htmlEscape="" scope="" var=""/>
  • property: 只允许指定Authentication所拥有的属性,可以进行属性的级联获取,如“principle.username”,不允许直接通过方法进行调用
  • htmlEscape:表示是否需要将html进行转义。默认为true。
  • scope:与var属性一起使用,用于指定存放获取的结果的属性名的作用范围,默认我pageContext。Jsp中拥有的作用范围都进行进行指定
  • var: 用于指定一个属性名,这样当获取到了authentication的相关信息后会将其以var指定的属性名进行存放,默认是存放在pageConext中

authorize

authorize是用来判断普通权限的,通过判断用户是否具有对应的权限而控制其所包含内容的显示

<security:authorize access="" method="" url="" var=""></security:authorize>
  • access: 需要使用表达式来判断权限,当表达式的返回结果为true时表示拥有对应的权限
  • method:method属性是配合url属性一起使用的,表示用户应当具有指定url指定method访问的权限,method的默认值为GET,可选值为http请求的7种方法
  • url:url表示如果用户拥有访问指定url的权限即表示可以显示authorize标签包含的内容
  • var:用于指定将权限鉴定的结果存放在pageContext的哪个属性中

accesscontrollist

accesscontrollist标签是用于鉴定ACL权限的。其一共定义了三个属性:hasPermission、domainObject和var,其中前两个是必须指定的

<security:accesscontrollist hasPermission="" domainObject="" var=""></security:accesscontrollist>
  • hasPermission:hasPermission属性用于指定以逗号分隔的权限列表
  • domainObject:domainObject用于指定对应的域对象
  • var:var则是用以将鉴定的结果以指定的属性名存入pageContext中,以供同一页面的其它地方使用
上一篇:常用数据库命令


下一篇:C#读写文本文件