⑦. 退出登录
7.
退出登录
- ①. 用户完成登录后Spring Security框架会记录当前用户认证状态为已认证状态,即表示用 户登录成功了。那用户如何退出登录呢?我们可以在spring-security.xml文件中进行如下 配置:
<!-- logout:退出登录 logout-url:退出登录操作对应的请求路径 logout-success-url:退出登录后的跳转页面 默认退出的url是/logout 注意:要求是post的提交方式提交 --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/>
- ②. 通过上面的配置可以发现,如果用户要退出登录,只需要请求/logout.do这个URL地址就 可以,同时会将当前session失效,最后页面会跳转到login.html页面
- ③.
注意:
默认退出的url是/logout | 要求是post的提交方式提交
⑧. 页面iframe设置为可访问[同源策略]
8.
iframe设置为可访问 [ 官方称为:同源策略 ]
<security:http auto-config="true" use-expressions="true"> <security:headers> <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问--> <security:frame-options policy="SAMEORIGIN"></security:frame-options> </security:headers> </security:http>
⑨. 登录成功获取用户姓名
- SecurityContextHolder.getContext().getAuthentication( ).getPrincipal( );
//获取当前用户登录的用户名 @RequestMapping("/getUsername") public Result getUsername(){ //spring security认证通过后,会将用户名存到框架的上下文对象中 //底层基于HttpSession try{ User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); return new Result(true, MessageConstant.GET_USERNAME_SUCCESS, user.getUsername()); }catch (Exception e){ e.getStackTrace(); return new Result(false,MessageConstant.GET_USERNAME_FAIL); } }
⑩. 登录日志的处理流程
10>.
登录成功处理器
- ①. spring security为我们提供了一个叫“登录成功处理器”的组件,我们可以实现在登录后进行的后续处理逻辑
//测试 public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler { public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { System.out.println(".........WO LAI LE"); request.getRequestDispatcher("/main.html").forward(request,response); } }
②. applicationContext_security.xml新增配置
<bean id="loginHandler" class="com.qingcheng.controller.AuthenticationSuccessHandlerImpl"></bean> <security:form-login login-page="/login.html" username-parameter="username" password-parameter="password" login-processing-url="/login.do" default-target-url="/main.html" authentication-failure-url="/login.html" authentication-success-handler-ref="loginHandler" ></security:form-login>
⑩. 实战演示
- ①. 需求:根据不同的用户授予不同的角色和权限
②. 导包
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring‐security‐web</artifactId> <version>5.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring‐security‐config</artifactId> <version>5.0.5.RELEASE</version> </dependency>
③. web.xml
<filter> <!-- DelegatingFilterProxy用于整合第三方框架 整合Spring Security时过滤器的名称必须为springSecurityFilterChain, 否则会抛出NoSuchBeanDefinitionException异常 --> <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[记得在spring-mvc.xml中引入文件]
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:security="http://www.springframework.org/schema/security" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd"> <!--配置哪些资源匿名可以访问(不登录也可以访问)--> <!--<security:http security="none" pattern="/pages/a.html"></security:http> <security:http security="none" pattern="/pages/b.html"></security:http>--> <!--<security:http security="none" pattern="/pages/**"></security:http>--> <security:http security="none" pattern="/login.html"></security:http> <security:http security="none" pattern="/css/**"></security:http> <security:http security="none" pattern="/img/**"></security:http> <security:http security="none" pattern="/js/**"></security:http> <security:http security="none" pattern="/plugins/**"></security:http> <!-- auto-config:自动配置,如果设置为true,表示自动应用一些默认配置,比如框架会提供一个默认的登录页面 use-expressions:是否使用spring security提供的表达式来描述权限 --> <security:http auto-config="true" use-expressions="true"> <security:headers> <!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问--> <security:frame-options policy="SAMEORIGIN"></security:frame-options> </security:headers> <!--配置拦截规则,/** 表示拦截所有请求--> <!-- pattern:描述拦截规则 asscess:指定所需的访问角色或者访问权限 --> <!--只要认证通过就可以访问--> <security:intercept-url pattern="/pages/**" access="isAuthenticated()" /> <!--如果我们要使用自己指定的页面作为登录页面,必须配置登录表单.页面提交的登录表单请求是由框架负责处理--> <!-- login-page:指定登录页面访问URL --> <security:form-login login-page="/login.html" username-parameter="username" password-parameter="password" login-processing-url="/login.do" default-target-url="/pages/main.html" authentication-failure-url="/login.html"></security:form-login> <!-- csrf:对应CsrfFilter过滤器 disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403) --> <security:csrf disabled="true"></security:csrf> <!-- logout:退出登录 logout-url:退出登录操作对应的请求路径 logout-success-url:退出登录后的跳转页面 --> <security:logout logout-url="/logout.do" logout-success-url="/login.html" invalidate-session="true"/> </security:http> <!--配置认证管理器--> <security:authentication-manager> <!--配置认证提供者--> <security:authentication-provider user-service-ref="springSecurityUserService"> <!-- 配置一个具体的用户,后期需要从数据库查询用户 <security:user-service> <security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"/> </security:user-service> --> <!--指定度密码进行加密的对象--> <security:password-encoder ref="passwordEncoder"></security:password-encoder> </security:authentication-provider> </security:authentication-manager> <!--配置密码加密对象--> <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> <!--开启注解方式权限控制--> <security:global-method-security pre-post-annotations="enabled" /> </beans>
④. UserService [ 重点掌握 ]
@Component public class SpringSecurityUserService implements UserDetailsService { //使用dubbo通过网络远程调用服务提供方获取数据库中的用户信息 @Reference private UserService userService; //根据用户名查询数据库获取用户信息 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userService.findByUsername2(username); if(user == null){ //用户名不存在 return null; } List<GrantedAuthority> list = new ArrayList<>(); //动态为当前用户授权 Set<Role> roles = user.getRoles(); for (Role role : roles) { //遍历角色集合,为用户授予角色 list.add(new SimpleGrantedAuthority(role.getKeyword())); Set<Permission> permissions = role.getPermissions(); for (Permission permission : permissions) { //遍历权限集合,为用户授权 list.add(new SimpleGrantedAuthority(permission.getKeyword())); } } org.springframework.security.core.userdetails.User securityUser = new org.springframework.security.core.userdetails.User(username,user.getPassword(),list); return securityUser; } }
⑤. mybatis 的sql编写 [ 重点掌握 ]
User: private Integer id; // 主键 private Date birthday; // 生日 private String gender; // 性别 private String username; // 用户名,唯一 private String password; // 密码 private String remark; // 备注 private String station; // 状态 private String telephone; // 联系电话 private Set<Role> roles = new HashSet<Role>(0);//对应角色集合
userDao.xml <resultMap id="baseMap" type="com.itheima.pojo.User"> <id column="id" property="id"></id> <result column="birthday" property="birthday"></result> <result column="gender" property="gender"></result> <result column="username" property="username"></result> <result column="password" property="password"></result> <result column="remark" property="remark"></result> <result column="station" property="station"></result> <result column="telephone" property="telephone"></result> </resultMap> <resultMap id="UserMap" type="com.itheima.pojo.User" extends="baseMap"> <!-- private Set<Role> roles = new HashSet<Role>(0);//对应角色集合--> <collection property="roles" ofType="com.itheima.pojo.Role" 这里的id是select * from t_user...查询出来的结果的id column="id" select="com.itheima.dao.RoleDao.findUserIdByRoles"> </collection> </resultMap> <select id="findByUsername2" parameterType="string" resultMap="UserMap"> select * from t_user where username=#{username} </select>
public class Role implements Serializable { private Integer id; private String name; // 角色名称 private String keyword; // 角色关键字,用于权限控制 private String description; // 描述 private Set<User> users = new HashSet<User>(0); private Set<Permission> permissions = new HashSet<Permission>(0); }
RoleDao.xml <resultMap id="baseMap" type="com.itheima.pojo.Role"> <id column="id" property="id"></id> <result column="name" property="name"></result> <result column="keyword" property="keyword"></result> <result column="description" property="description"></result> </resultMap> <resultMap id="RolesMap" type="com.itheima.pojo.Role" extends="baseMap"> <collection property="permissions" column="id" ofType="com.itheima.pojo.Permission" select="com.itheima.dao.PermissionDao.findRoleIdsByPserssion"> </collection> <select id="findUserIdByRoles" resultMap="RolesMap" parameterType="int"> select * from t_role where id in(select role_id from t_user_role where user_id=#{user_id}) </select>
perssionDao.xml <select id="findRoleIdsByPserssion" resultType="com.itheima.pojo.Permission" parameterType="int"> select * from t_permission where id in(select permission_id from t_role_permission where role_id=#{role_id}) </select>