BAT大牛亲授基于ElasticSearch的搜房网实战(第五章后台管理模块开发)

从零起步基于ElasticSearch的搜房网(前后端集成)实战(介绍与整体目录)点击即可

静态资源集成太多页面,我已经上传到博客资源链接,供下载。后期代码全部完善后,会上传到github上。

静态资源链接下载点击

 业务与功能分析:

 本章主要实现的功能:

  1. 后台登录
  2. 权限控制
  3. 注销功能

使用基于hui的后台管理模板

开始代码逻辑:

首先在controller中新建一个admin的package,然后再admin文件夹中新建一个AdminController的类。

 

AdminController:
package liangliang.bigdata.web.controller.admin;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class AdminController {
    @GetMapping("/admin/center")
    public String AdminCenterPage(){
        return "admin/center";
    }
    @GetMapping("/admin/welcome")
    public String AdminWelcomePage(){
        return "admin/welcome";
    }
    @GetMapping("/admin/login")
    public String AdminLoginPage(){
        return "admin/login";
    }
}

在templates文件夹中新建admin文件夹,在admin中新建三个html页面:center.html、welcome.html、login.html

center.html:

<!--_meta 作为公共模版分离出去-->
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<div th:include="admin/common :: head"></div>
<div th:include="admin/common :: header"></div>

<body>
<div th:include="admin/common :: left_menu"></div>
<section class="Hui-article-box">
    <div id="Hui-tabNav" class="Hui-tabNav hidden-xs">
        <div class="Hui-tabNav-wp">
            <ul id="min_title_list" class="acrossTab cl">
                <li class="active">
                    <span title="我的桌面" data-href="welcome.html">我的桌面</span>
                    <em></em></li>
            </ul>
        </div>
        <div class="Hui-tabNav-more btn-group"><a id="js-tabNav-prev" class="btn radius btn-default size-S"
                                                  href="javascript:;"><i class="Hui-iconfont">&#xe6d4;</i></a><a
                id="js-tabNav-next" class="btn radius btn-default size-S" href="javascript:;"><i class="Hui-iconfont">&#xe6d7;</i></a>
        </div>
    </div>
    <div id="iframe_box" class="Hui-article">
        <div class="show_iframe">
            <div style="display:none" class="loading"></div>
            <iframe scrolling="yes" frameborder="0" src="welcome.html"></iframe>
        </div>
    </div>
</section>

<div class="contextMenu" id="Huiadminmenu">
    <ul>
        <li id="closethis">关闭当前</li>
        <li id="closeall">关闭全部</li>
    </ul>
</div>
<div th:include="admin/common :: footer">
</div>

<!--请在下方写此页面业务相关的脚本-->
<script type="text/javascript" src="/static/lib/jquery.contextmenu/jquery.contextmenu.r2.js"></script>
<div th:include="admin/common :: house_manage"></div>
</body>
</html>

login.html:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <title>寻屋-后台登录系统</title>

    <!--- CSS --->
    <link rel="stylesheet" href="/static/css/admin/login-style.css" type="text/css" />


    <!--- Javascript libraries (jQuery and Selectivizr) used for the custom checkbox --->

    <!--[if (gte IE 6)&(lte IE 8)]>
    <script type="text/javascript" src="/static/lib/jquery/1.9.1/jquery.js"></script>
    <script type="text/javascript" src="/static/js/admin/selectivizr.js"></script>
    <noscript><link rel="stylesheet" href="/static/css/admin/login-fallback.css" /></noscript>
    <![endif]-->

</head>

<body>
<div id="container">
    <form action="#" th:action="@{/login}" method="post">
        <div class="login">管理员登录</div>
        <div th:if="${param.error}" style="position: absolute; color: red; padding-top: 6%; padding-left: 3%">
            非法的用户名或密码
        </div>
        <div class="username-text">用户名:</div>
        <div class="password-text">密码:</div>
        <div class="username-field">
            <input type="text" name="username" placeholder="请输入用户名"/>
        </div>
        <div class="password-field">
            <input type="password" name="password" placeholder="请输入密码" />
        </div>


        <!--<input type="checkbox" name="remember-me" id="remember-me" /><label for="remember-me">Remember me</label>-->
        <!--<div class="forgot-usr-pwd">Forgot <a href="#">username</a> or <a href="#">password</a>?</div>-->

        <div class="login-button">
            <button type="submit" class="login_button">登录</button>
        </div>
    </form>
</div>
<div id="footer">
    寻屋-后台管理系统 <a href="#" target="_blank" title="登录"></a>
</div>
</body>
</html>

welcome.html:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:include="admin/common :: head">
    <title>我的桌面</title>
</head>
<body>
<div class="page-container">
    <p style="height: 50px;" class="f-20 text-success">欢迎来到七天共享云平台 <span class="f-14">^_^</span>祝亲共享愉快!</p>
    <div><img style="text-align: center" src="/static/images/day_welcom.gif" height="100%" width="100%"></div>
</div>
</body>
</html>

先访问我们的路由:http://127.0.0.1:8080/admin/login

 

整体模块下图:

在WebMvcConfig中添加支持SpringSecurity的方言:

WebMvcConfig:
package liangliang.bigdata.config;

import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;

@Configuration
//帮助我们获取spring的上下文
public class WebMvcConfig extends WebMvcConfigurerAdapter implements ApplicationContextAware {
    //私有化一个类
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //配置静态资源

        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }


    /**
     * 对模板资源进行解析
     * 模板资源解析器
     */
    @Bean
    //做一个前缀绑定,否则找不到路径
    @ConfigurationProperties(prefix = "spring.thymeleaf")
    public SpringResourceTemplateResolver templateResolver (){
        //实例化一个
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        //设置spring的上下文
        templateResolver.setApplicationContext(this.applicationContext);
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }
    /**
     * Thymeleaf标准方言解析器
     */
    @Bean
    public SpringTemplateEngine templateEngine(){
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        //配置资源解析器的引擎
        templateEngine.setTemplateResolver(templateResolver());
        //设置支持EL表达式
        templateEngine.setEnableSpringELCompiler(true);
        //支持SpringSecurity方言
        SpringSecurityDialect springSecurityDialect = new SpringSecurityDialect();
        templateEngine.addDialect(springSecurityDialect);

        return templateEngine;
    }
    /**
     * 视图解析器
     */
    @Bean
    public ThymeleafViewResolver viewResolver(){
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
        //配置Thymeleaf标准方言解析器
        viewResolver.setTemplateEngine(templateEngine());
        return viewResolver;
    }



}

在config的文件夹中新建一个 WebSecurityConfig类:

WebSecurityConfig:
package liangliang.bigdata.config;

import liangliang.bigdata.security.AuthProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;



@EnableWebSecurity
@EnableGlobalMethodSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    /**
     * HTTP权限控制
     */
    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception{
        //资源访问权限
        httpSecurity.authorizeRequests().antMatchers("/admin/login").permitAll()//管理员登录入口
                .antMatchers("/static/**").permitAll()//静态资源
                .antMatchers("user/login").permitAll()//用户登录入口
                .antMatchers("/admin/**").hasAnyRole("ADMIN","USER")
                .antMatchers("/api/user/**").hasAnyRole("ADMIN","USER")
                .and()
                .formLogin()
                .loginProcessingUrl("/login")//配置角色登录处理入口
                .and();
        httpSecurity.csrf().disable();//防御策略
        httpSecurity.headers().frameOptions();

    }
    /**
     * 自定义认证策略
     * @EnableWebSecurity
     * @EnableGlobalMethodSecurity
     * 在以上这两个任意一个下面只有这个
     * AuthenticationManagerBuilder
     *
     */
    @Autowired
    public void configGlobal(AuthenticationManagerBuilder auth){
       // 配置内存用户名和密码
        auth.authenticationProvider(authProvider()).eraseCredentials(true);
    }
    @Bean
    public AuthProvider authProvider(){
        return new AuthProvider();
    }
}

在repository中新建一个借口(RoleRepository):

RoleRepository:
package liangliang.bigdata.repository;

import liangliang.bigdata.entity.Role;
import org.springframework.data.repository.CrudRepository;

import java.util.List;
//一个对应实体类,一个对应我们的id

/**
 * 角色数据DAO层
 */
public interface RoleRepository extends CrudRepository<Role,Long> {
    List<Role> findRoleByUserId (Long userId);
}

新建一个security文件夹,在里面新建一个AuthProvider类:

AuthProvider :
package liangliang.bigdata.security;

import liangliang.bigdata.entity.User;
import liangliang.bigdata.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.authentication.encoding.Md5PasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

/**
 * 自定义认证实现
 */
public class AuthProvider implements AuthenticationProvider {
    private final Md5PasswordEncoder passwordEncoder = new Md5PasswordEncoder();
    @Autowired
    private IUserService userService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String userName = authentication.getName();
        String inputPassword = (String) authentication.getCredentials();
        User user = userService.findUserByName(userName);
        if (user == null) {
            throw new AuthenticationCredentialsNotFoundException("用户不存在");
        }
        //使用用户id作为加盐
        if (this.passwordEncoder.isPasswordValid(user.getPassword(), inputPassword, user.getId())) {
            return new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
        }
        throw new BadCredentialsException("authError");
    }
    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}

新建一个service文件夹在service从中新建一个user文件夹,并且在service新建一个IUserService接口:

IUserService:
package liangliang.bigdata.service;

import liangliang.bigdata.entity.User;

/**
 * 用户服务
 */
public interface IUserService {
    User findUserByName (String userName);
}

在service的user文件夹中新建一个UserServiceImpl类:

 UserServiceImpl :
package liangliang.bigdata.service.user;

import liangliang.bigdata.entity.Role;
import liangliang.bigdata.entity.User;
import liangliang.bigdata.repository.RoleRepository;
import liangliang.bigdata.repository.UserRepository;
import liangliang.bigdata.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private RoleRepository roleRepository;
    //user的包装
    @Override
    public User findUserByName(String userName) {
        User user = userRepository.findByName(userName);
        if(user == null){
            return null;
        }
        List<Role> roles = roleRepository.findRoleByUserId(user.getId());
        if (roles == null){
            throw new DisabledException("权限非法");
        }
        List<GrantedAuthority>authorities = new ArrayList<>();
        roles.forEach(role -> authorities.add(new SimpleGrantedAuthority("ROLE_"+role.getName())));
        return user;
    }
}

在entity中的两个实体类,一个是User一个是Role:

User:
package liangliang.bigdata.entity;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import javax.persistence.*;
import java.util.Collection;
import java.util.Date;
import java.util.List;

@Entity
//注意数据库中的user是小写的,需要注意一下与数据库中做一个映射
@Table(name = "user")
public class User implements UserDetails {
    @Id
    //因为同时兼容hibernate和H2
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    //主键
    private Long id;
    //姓名
    private String name;
    //密码
    private String password;
    //邮箱
    private String email;
    //电话号码 做一个映射与数据库
    @Column(name = "phone_number")
    private  String phoneNumber;
    //状态码
    private int status;
    //创建时间
    @Column(name="create_time")
    private Date createTime;
    //最后登录时间
    @Column(name = "last_login_time")
    private Date lastLoginTime;
    @Column(name = "last_update_time")
    private Date lastUpdateTime;
    //头像
    private String avatar;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    public String getPassword() {
        return password;
    }

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

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

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

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

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

    public void setPassword(String password) {
        this.password = password;
    }
    //权限给一个新的属性
   //为了让他透明,不需要验证这个字段
    @Transient
    private List<GrantedAuthority> authorityList;
    public List<GrantedAuthority>getAuthorityList(){
        return authorityList;
    }

    public void setAuthorityList(List<GrantedAuthority> authorityList) {
        this.authorityList = authorityList;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    public Date getLastLoginTime() {
        return lastLoginTime;
    }

    public void setLastLoginTime(Date lastLoginTime) {
        this.lastLoginTime = lastLoginTime;
    }

    public Date getLastUpdateTime() {
        return lastUpdateTime;
    }

    public void setLastUpdateTime(Date lastUpdateTime) {
        this.lastUpdateTime = lastUpdateTime;
    }

    public String getAvatar() {
        return avatar;
    }

    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }
}

Role:

package liangliang.bigdata.entity;

import javax.persistence.*;

@Entity
@Table(name = "role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "user_id")
    private Long userId;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getUserId() {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

index.html:

<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta http-equiv="Cache-Control" content="no-transform"/>
    <meta http-equiv="Cache-Control" content="no-siteapp"/>
    <meta http-equiv="Content-language" content="zh-CN"/>
    <meta name="format-detection" content="telephone=no"/>
    <meta name="applicable-device" content="pc">

    <title>寻屋</title>
    <meta name="description" content="方便快捷寻屋"/>
    <meta name="keywords" content="寻屋"/>
    <link href="/static/css/main.css" rel='stylesheet' type='text/css'/>
    <link href="/static/css/index.css" rel='stylesheet' type='text/css'/>
</head>
<body>
<header th:replace="common :: header"></header>

<div class="city-change animated bounceIn" style="display: block;">
    <span class="close"></span>
    <div class="title">选择城市
        <span class="city-tab">
            <span class="code1">热门城市:</span>
            <a href="/rent/house?cityEnName=bj" title="北京租房">北京</a>
            <a href="/rent/house?cityEnName=sh" title="上海租房">上海</a>
            <a href="/rent/house?cityEnName=gz" title="广州租房">广州</a>
            <a href="/rent/house?cityEnName=sz" title="深圳租房">深圳</a>
        </span>
    </div>
    <div class="title-line"></div>
    <div class="fc-main clear">
        <div class="fl citys-l">
            <ul>
                <li class="clear"><span class="code-title fl">B</span>
                    <div class="city-enum fl"><a href="/rent/house?cityEnName=bj" title="北京租房">北京</a></div>
                </li>
                <li class="clear"><span class="code-title fl">C</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=cd" title="成都租房">成都</a>
                        <a href="/rent/house?cityEnName=cq" title="重庆租房">重庆</a>
                        <a href="/rent/house?cityEnName=cs" title="长沙租房">长沙</a>
                    </div>
                </li>
                <li class="clear"><span class="code-title fl">D</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=dl" title="大连租房">大连</a>
                        <a href="/rent/house?cityEnName=dg" title="东莞租房">东莞</a>
                    </div>
                </li>
                <li class="clear"><span class="code-title fl">F</span>
                    <div class="city-enum fl"><a href="/rent/house?cityEnName=fs" title="佛山租房">佛山</a></div>
                </li>
                <li class="clear"><span class="code-title fl">G</span>
                    <div class="city-enum fl"><a href="/rent/house?cityEnName=gz" title="广州租房">广州</a></div>
                </li>
                <li class="clear"><span class="code-title fl">H</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=hz" title="杭州租房">杭州</a>
                        <a href="/rent/house?cityEnName=hui" title="惠州租房">惠州</a>
                        <a href="/rent/house?cityEnName=hk" title="海口租房">海口</a>
                        <a href="/rent/house?cityEnName=hf" title="合肥租房">合肥</a>
                    </div>
                </li>
            </ul>
        </div>
        <div class="fl citys-r">
            <ul>
                <li class="clear">
                    <span class="code-title fl">L</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=ls" title="陵水租房">陵水</a>
                        <a href="/rent/house?cityEnName=lf" title="廊坊租房">廊坊</a>
                    </div>
                </li>
                <li class="clear">
                    <span class="code-title fl">N</span>
                    <div class="city-enum fl"><a href="/rent/house?cityEnName=nj" title="南京租房">南京</a></div>
                </li>
                <li class="clear">
                    <span class="code-title fl">Q</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=qd" title="青岛租房">青岛</a>
                        <a href="/rent/house?cityEnName=qh" title="琼海租房">琼海</a>
                    </div>
                </li>
                <li class="clear">
                    <span class="code-title fl">S</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=sh" title="上海租房">上海</a>
                        <a href="/rent/house?cityEnName=sz" title="深圳租房">深圳</a>
                        <a href="/rent/house?cityEnName=su" title="苏州租房">苏州</a>
                        <a href="/rent/house?cityEnName=sjz" title="石家庄租房">石家庄</a>
                        <a href="/rent/house?cityEnName=sy" title="沈阳租房">沈阳</a>
                        <a href="/rent/house?cityEnName=sanya" title="三亚租房">三亚</a>
                    </div>
                </li>
                <li class="clear">
                    <span class="code-title fl">T</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=tj" title="天津租房">天津</a>
                        <a href="/rent/house?cityEnName=ty" title="太原租房">太原</a>
                    </div>
                </li>
                <li class="clear">
                    <span class="code-title fl">W</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=wh" title="武汉租房">武汉</a>
                        <a href="/rent/house?cityEnName=wx" title="无锡租房">无锡</a>
                        <a href="/rent/house?cityEnName=wc" title="文昌租房">文昌</a>
                        <a href="/rent/house?cityEnName=wn" title="万宁租房">万宁</a>
                    </div>
                </li>
                <li class="clear">
                    <span class="code-title fl">X</span>
                    <div class="city-enum fl">
                        <a href="/rent/house?cityEnName=xm" title="厦门租房">厦门</a>
                        <a href="/rent/house?cityEnName=xa" title="西安租房">西安</a>
                        <a href="/rent/house?cityEnName=xsbn" title="西双版纳租房">西双版纳</a></div>
                </li>
            </ul>
        </div>
    </div>
</div>


<div th:include="common :: footer"></div>
<script th:inline="javascript" type="text/javascript">
    $(function () {
        $('.xunwu-header .index-page').addClass('on');

        function msgTip(content) {
            layer.open({
                type: 1,
                offset: '100px',
                area: ['420px', '240px'],
                skin: 'layui-layer-lan', //样式类名
                closeBtn: 1, //显示关闭按钮
                anim: 2,
                shadeClose: true, //开启遮罩关闭
                content: content,
                time: 2000
            });
        }

        var msg = [[${msg}]];
        if (msg === 'must_chose_city') {
            msgTip('<p class="msgTip">你必须选择一个城市</p>');
        } else if (msg === 'not_support_city') {
            msgTip('<p class="msgTip">暂不支持所选城市</p>');
        } else {
            // TODO
        }
    });
</script>
</body>
</html>

现在我们可以运行看一下效果:密码:admin,账号admin

 

后台管理模块

  1. 后台整体界面
  2. 登录功能
  3. 角色权限控制

整体模块如下图所示:

更新后的WebSecurityConfig:
package liangliang.bigdata.config;

import liangliang.bigdata.security.AuthProvider;
import liangliang.bigdata.security.LoginAuthFailHander;
import liangliang.bigdata.security.LoginUrlEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
@EnableGlobalMethodSecurity
public class WebSecurityConfig  extends WebSecurityConfigurerAdapter{
    /**
     * Http权限控制
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        http.addFilterBefore(authFilter(), UsernamePasswordAuthenticationFilter.class);
        //资源访问权限
        http.authorizeRequests()
                .antMatchers("/admin/login").permitAll()//管理员登录入口
                .antMatchers("/static/**").permitAll()//静态资源
                .antMatchers("/user/login").permitAll()//用户登录入口
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**").hasAnyRole("ADMIN","USER")
                .antMatchers("/api/user/**").hasAnyRole("ADMIN","USER")
                .and()
                .formLogin()
                .loginProcessingUrl("/login")//配置之角色登录处理入口
                .failureHandler(authFailHandler())
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessUrl("/logout/page")
                .deleteCookies("JESSIONID")
                .invalidateHttpSession(true)
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(urlEntryPoint())
                .accessDeniedPage("/403");
        http.csrf().disable();
        http.headers().frameOptions().sameOrigin();
    }
    /**
     * 自定义认证策略
     * @throws Exception
     */
    @Autowired
    public void configGlobal(AuthenticationManagerBuilder auth) throws Exception {
        //auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN").and();
        auth.authenticationProvider(authProvider()).eraseCredentials(true);
    }

    @Bean
    public AuthProvider authProvider() {
        return new AuthProvider();
    }

    @Bean
    public LoginUrlEntryPoint urlEntryPoint() {
        return new LoginUrlEntryPoint("/user/login");
    }

    @Bean
    public LoginAuthFailHander authFailHandler() {
        return new LoginAuthFailHander(urlEntryPoint());
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        AuthenticationManager authenticationManager = null;
        try {
            authenticationManager =  super.authenticationManager();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return authenticationManager;
    }

//    @Bean
//    public AuthFilter authFilter() {
//        AuthFilter authFilter = new AuthFilter();
//        authFilter.setAuthenticationManager(authenticationManager());
//        authFilter.setAuthenticationFailureHandler(authFailHandler());
//        return authFilter;
//    }
}

 基于角色登录入口的控制器:

LoginUrlEntryPoint:
package liangliang.bigdata.security;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 基于角色的登录入口控制器
 */
public class LoginUrlEntryPoint extends LoginUrlAuthenticationEntryPoint {

    private static final String API_FREFIX = "/api";
    private static final String API_CODE_403 = "{\"code\": 403}";
    private static final String CONTENT_TYPE = "application/json;charset=UTF-8";

    private PathMatcher pathMatcher = new AntPathMatcher();
    private final Map<String, String> authEntryPointMap;

    public LoginUrlEntryPoint(String loginFormUrl) {
        super(loginFormUrl);
        authEntryPointMap = new HashMap<>();

        // 普通用户登录入口映射
        authEntryPointMap.put("/user/**", "/user/login");
        // 管理员登录入口映射
        authEntryPointMap.put("/admin/**", "/admin/login");
    }

    /**
     * 根据请求跳转到指定的页面,父类是默认使用loginFormUrl
     * @param request
     * @param response
     * @param exception
     * @return
     */
    @Override
    protected String determineUrlToUseForThisRequest(HttpServletRequest request, HttpServletResponse response,
                                                     AuthenticationException exception) {
        String uri = request.getRequestURI().replace(request.getContextPath(), "");

        for (Map.Entry<String, String> authEntry : this.authEntryPointMap.entrySet()) {
            if (this.pathMatcher.match(authEntry.getKey(), uri)) {
                return authEntry.getValue();
            }
        }
        return super.determineUrlToUseForThisRequest(request, response, exception);
    }
}
登录验证失败处理器
LoginAuthFailHander:
package liangliang.bigdata.security;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 登录验证失败处理器
 * Created by 瓦力.
 */
public class LoginAuthFailHander extends SimpleUrlAuthenticationFailureHandler {
    private final LoginUrlEntryPoint urlEntryPoint;

    public LoginAuthFailHander(LoginUrlEntryPoint urlEntryPoint) {
        this.urlEntryPoint = urlEntryPoint;
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                        AuthenticationException exception) throws IOException, ServletException {
        String targetUrl =
                this.urlEntryPoint.determineUrlToUseForThisRequest(request, response, exception);

        targetUrl += "?" + exception.getMessage();
        super.setDefaultFailureUrl(targetUrl);
        super.onAuthenticationFailure(request, response, exception);
    }
}

运行一下看效果,其他没更新的就是,暂时不需要改变的。

管理员登录中心:

用户登录:

验证失败逻辑显示:

 

 用户登录中心:

上篇博客:基于ElasticSearch的搜房网实战(第四章第四章环系统架构设计与分层)

下篇博客:基于ElasticSearch的搜房网实战(第六章房源信息管理模块实现)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值