springboot+shiro+md5

这里详细记录一次springboot使用shiro进行登录验证操作,同时结合MD5加密技术,实现web后台的登录功能。这里并不进行shiro认证框架的分析介绍,知识介绍一下如何使用。

:一:首先是pom.xml清单

        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>1.3.2</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!--Shiro核心框架 -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<!-- Shiro使用Srping框架 -->
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<!--md5加密-->
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.6</version>
		</dependency>

二:shiro配置

@Configuration
public class ShiroConfig {

    private static String loginUrl = "/login";

    @Bean
    public UserRealm userRealm(){
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }

    /*
    配置安全管理器
     */
    @Bean
    public SecurityManager manager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        return securityManager;
    }

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager manager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(manager);
        //身份认证失败,则跳转到登录页面的配置
        bean.setLoginUrl(loginUrl);
        // Shiro连接约束配置,即过滤链的定义
        LinkedHashMap<String,String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 对静态资源设置匿名访问
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/bootstrap/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/font-awesome/**", "anon");
        filterChainDefinitionMap.put("/images/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/layer/**", "anon");
        filterChainDefinitionMap.put("/ico/**", "anon");

        // 不需要拦截的访问
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/do_login", "anon");

        // 所有请求需要认证
        filterChainDefinitionMap.put("/**", "authc");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }

}

这里需要注意,需要把login和do_login这两个url的拦截给忽略掉,否则会被拦截,无法进行登录操作。

3:编写realm模块,继承自AuthorizingRealm类并重写其中的两个方法doGetAuthorizationInfo和doGetAuthenticationInfo两个方法,前者为权限管理处理方法,后者是处理身份认证的处理方法,也就是我们这次的重点,权限处理暂时不处理。

public class UserRealm extends AuthorizingRealm{

    @Autowired
    LoginService loginService;

    /*
    处理权限
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        return null;
    }

    /*
    处理认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken token1 = (UsernamePasswordToken) token;
        String username = token1.getUsername();
        String password = "";
        if (token1.getPassword() != null){
            password = new String(token1.getPassword());
        }
        User user = null;
        System.out.println("用户名"+username+"密码"+password);
        user = loginService.login(username,password);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,password,getName());
        return info;
    }
}

注意SimpleAuthenticationInfo类我们并没有把salt给上去,这里的密码加解密由我们自己是实现。

4:编写LoginController处理前端的登录操作

@Controller
public class LoginController {

    @RequestMapping("/login")
    public String loginPage(){
        System.out.println("访问page");
        return "login";
    }

    //ajax执行登录操作
    @RequestMapping(value = "/do_login",method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult login(String username, String password, HttpSession session){
        System.out.println("访问lgon");
        //再进行一遍MD5加密
        String realPassword = MD5Utils.formPassToDbPass(password);
        UsernamePasswordToken token = new UsernamePasswordToken(username,realPassword);
        Subject subject = SecurityUtils.getSubject();
        try{
            subject.login(token);
            session.setAttribute("user", subject.getPrincipal());
        }catch (Exception e){
            e.printStackTrace();
        }
        System.out.println("do_login"+" "+AjaxResult.success("登陆成功"));
        return AjaxResult.success("登录成功");
    }

    @RequestMapping("/home")
    public String index(){
        return "index";
    }
}

在login方法中,我们拿到的password是前端用户输完密码后的一次md5加密后的密码,前端加密下边会讲到,我们拿到这个password后再进行一边加密操作,然后生成token,交给subject去进行登录操作,最后返回我们封装好的AjaxResult,返回到前端为json类型,MD5Utils类如下:

public class MD5Utils {
    private static final String SALT = "1a2b3c4d";

    private static String md5(String pass){
        return DigestUtils.md5Hex(pass);
    }

    //表单到后台的加密
    public static String inputPassToFormPass(String inputPass){
        String saltPass = "" + SALT.charAt(0) + SALT.charAt(2) + inputPass + SALT.charAt(5) + SALT.charAt(4);
        return md5(saltPass);
    }

    //后台到数据库的加密
    public static String formPassToDbPass(String formPass){
        String saltPass = "" + SALT.charAt(0) + SALT.charAt(2) + formPass + SALT.charAt(5) + SALT.charAt(4);
        return saltPass;
    }

    //综合两种加密
    public static String inputPassToDbPass(String inputPass){
        String realPass = formPassToDbPass(inputPassToFormPass(inputPass));
        return realPass;
    }

    public static void main(String[] args) {
        String realPass = inputPassToDbPass("1234");
        System.out.println(realPass);
    }
}

这里的盐我们写死在这里,实际项目中用该不会这么做,数据库中的密码也是我们提前用这个工具类手动生成的,这步可以写成一个注册的操作。

5:前端页面login.html的编写,需要注意的是,我们取消了form表单的submit提交功能,交由onclick的login()方法去处理。

<form id="loginForm" onsubmit="return false" method="post" action="##">
                            <div class="form-group">
                                <label class="sr-only" for="username">用户名</label>
                                <input type="text" name="username" placeholder="用户名" class="form-first-name form-control" id="username">
                            </div>
                            <div class="form-group">
                                <label class="sr-only" for="password">密码</label>
                                <input type="text" name="password" placeholder="密 码" class="form-last-name form-control" id="password">
                            </div>
                            <button class="btn" type="button" onclick="login()">确认登录</button>
                        </form>

login方法如下,拿到用户输入的密码,进行一次md5加密,然后使用ajax向后台请求。若返回结果成功,则进行页面跳转。

var salt = "1a2b3c4d";
function showLoading() {
    var idx = layer.msg('处理中...', {icon: 16,shade: [0.5, '#f5f5f5'],scrollbar: false,offset: '0px', time:100000}) ;
    return idx;
}

function login() {
    showLoading();
    var inputPass = $("#password").val();
    var username = $("#username").val();
    if (inputPass.length == 0 || username.length == 0){
        alert("用户名或密码不允许为空");
        layer.closeAll();
    }else{
        var str = salt.charAt(0)+salt.charAt(2) + inputPass +salt.charAt(5) + salt.charAt(4);
        var password = md5(str);
        $.ajax({
            url:"/do_login",
            type:"post",
            data:{
                username:username,
                password:password
            },
            success:function (datas) {
                layer.closeAll();
                //根据返回的码判断结果
                console.log(datas);
                if(datas.code == 1){
                    layer.msg("登录成功");
                    window.location.href="/home";
                }else{
                    layer.msg(datas.msg);
                }
            }
        })
    }

}

6:验证

当你没有进行登录的时候,进入任何界面都会先跳转到登录界面,登录完成后跳转到指定页面。

7:整个demo这里是下载链接,欢迎大家下载并指正。

https://download.csdn.net/download/fly_rice/10557890

猜你喜欢

转载自blog.csdn.net/fly_rice/article/details/81162022
今日推荐